DDS-RPC 1.0 — Spec Coverage

Source: internal/standards/cache/omg/dds-rpc-1.0.pdf (68 pages, OMG formal/2017-04-01) — OMG DDS-RPC 1.0

Item-by-item audit against the PDF according to internal/spec-coverage/PROCESS.md. Page numbers are PDF pages (PDF page = printed page + 4). Every rule of the mapping to topics and types, every annotation, every field of the discovery extensions, every rule of interface evolution, every step of the correlation and every class of the language bindings is an item of its own. done stands only where code and test cover the requirement; a test citation names the test function as file::module::name. A repository citation names file and symbol; the commits that met a requirement are given with their 12-character hash at the item. Every statement about behaviour is read from the code. Nothing was run on the Mac (it only compiles there). The tests ran on a Linux test host in rounds 1 to 10; round 10 had no failure (source: results of the maintainer’s test runs, not part of this file).

Context: DDS-RPC is spread over these parts of ZeroDDS:

  • crates/rpc/ · docs.rs — the Rust runtime (Requester, Replier, wire_codec), the data model of the mapping (service_mapping, codegen, enhanced), topic names (topic_naming), annotations (annotations), common types (common_types), a pair of types with its own header (type_pair, header_pair), function-call (function_call), a reader for service definitions in Java (java_service_def), tables of the language bindings (language_binding), QoS (qos_profile), discovery data (discovery_ext, endpoint), a table of interface evolution (evolution_rules).
  • crates/lang-rules/src/adapter/interface.rs · docs.rs — the reader of an IDL interface for the generators; crates/lang-rules/src/emit/interface_cpp.rs with interface_cpp/, interface_java.rs with interface_java/ and interface_rust.rs with interface_rust/ — generated code for C++, Java and Rust (Basic and Enhanced, function-call and pair of types).
  • runtime/cpp/include/dds/rpc.hpp — the runtime of the C++ binding; runtime/cpp/include/dds/rpc/zerodds.hpp — its connection to the ZeroDDS C API.
  • runtime/java/src/main/java/org/omg/dds/rpc/ (the interfaces of the spec) and runtime/java/src/main/java/org/zerodds/ddsrpc/ (the implementations RequesterImpl, ReplierImpl, ServerImpl) — the runtime of the Java binding. runtime/java/src/main/java/org/zerodds/ddsrpc/ (ZeroDdsParticipant, RawTypeSupport) connects it to the DDS Java PSM implementation in crates/java-omgdds/, including PID_RELATED_SAMPLE_IDENTITY (merge a2a9a67acb58). The tests of the runtime also use an in-memory loop (crates/rpc/tests/java/RpcRuntimeRoundtrip.java).
  • crates/rtps/ · docs.rs — parameter IDs 0x0080 to 0x0083 and their codecs; crates/dcps/src/runtime.rs — sending and receiving PID_RELATED_SAMPLE_IDENTITY and the discovery extensions.
  • crates/zerodds-c-api/ · docs.rs — functions for RPC: zerodds_writer_write_related, zerodds_reader_take_wire, rpc_discovery_ffi.rs, rpc_profile_ffi.rs, rpc_qos_ffi.rs; the feature rpc gates rpc_discovery_ffi.rs and rpc_profile_ffi.rs.
  • crates/rpc-rust-e2e/ — the generated Rust binding over a real DcpsRuntime on loopback.

The specification defines language bindings for C++ and Java (§7.11). The Rust API in crates/rpc/ and the generated Rust binding are not a binding of the specification; they are cited where they carry the behaviour a rule requires. Where the runtimes for Rust, C++ and Java differ, the item says so. Further languages of the generators (C#, Go, TypeScript and others) are not governed by the specification and are not listed as items. The specification has no C binding; the ZeroDDS C API carries the functions the C++ binding builds on (see above) and is not itself a binding of the specification.

The specification names three machine-readable files as normative (omg-dds-rpc-cxx.zip, omg-dds-rpc-java.zip, omg-dds-rpc-idl.zip, p. 1). They are in internal/standards/cache/omg/ and compared: the C++ headers lie unchanged in runtime/cpp/include/dds/rpc/normative/ (item on §7.11.1), the Java files signature by signature against the Java runtime (SpecSignatureCheck, item on §7.11.2), robot.idl against the names of the generators (crates/lang-rules/tests/rpc_idl_zip_agrees.rs).

Open items: none; every item is done or n/a (informative).


§1 Scope

§1 Scope

Spec: §1, p. 13 — “This specification defines a Remote Procedure Calls (RPC) framework using the basic building blocks of DDS, such as topics, types, DataReaders, and DataWriters to provide request/reply semantics. […] It supports synchronous and asynchronous method invocation.”

Repo: —

Tests: —

Status: n/a (informative) — overview; the building blocks and the kinds of invocation are listed in §7 individually.


§2 Conformance

§2 Conformance points Basic and Enhanced

Spec: §2, p. 13 — “This specification defines two conformance points: Basic and Enhanced. [1] Basic conformance (mandatory) [2] Enhanced conformance (optional)”.

Repo: —

Tests: —

Status: n/a (informative) — assignment; whether a point is met follows from the status of the assigned items.

§2 Basic conformance — assignment

Spec: §2, p. 13 — “The basic conformance point includes support for the Basic service mapping and both the functional and the request-reply language binding styles.”

Repo: —

Tests: —

Status: n/a (informative) — assignment; the Basic mapping is in §7.4.2, §7.5.1.1, §7.6.1, §7.7.1 and §7.8.1, the two styles in §7.2.2 and §7.11.

§2 Enhanced conformance — assignment

Spec: §2, p. 13 — “The enhanced conformance point includes the basic conformance and adds support for the Enhanced Service mapping.”

Repo: —

Tests: —

Status: n/a (informative) — assignment; the Enhanced mapping is in §7.4.3, §7.5.1.2, §7.6.2, §7.7.2 and §7.8.2.


§3 Normative References

§3 Normative References

Spec: §3, pp. 13–14 — [DDS] 1.2, [RTPS], [DDS-Xtypes] 1.0 Beta 1, [CORBA] 3.3, [IDL35], [EBNF], [Java-Grammar], [DDS-Cxx-PSM], [DDS-Java-PSM], [DDS4CCM], [IDL2Java], [SOA-RM].

Repo: —

Tests: —

Status: n/a (informative) — bibliography; where a referenced standard carries a requirement (grammar of IDL and Java, DDS-Cxx-PSM, DDS-Java-PSM, DDS4CCM), it is listed with the item that uses it.


§4 Terms and Definitions

§4 Service, Remote Procedure Call

Spec: §4, p. 14 — definitions of “Service” (after [SOA-RM]) and “Remote Procedure Call”.

Repo: —

Tests: —

Status: n/a (informative) — terms.


§5 Symbols and Abbreviated Terms

§5 Abbreviations

Spec: §5, p. 14 — DDS, GUID, RPC, RTPS, SN.

Repo: —

Tests: —

Status: n/a (informative) — abbreviations.


§6 Additional Information

§6.1 Acknowledgements

Spec: §6.1, p. 15 — submitting and supporting companies.

Repo: —

Tests: —

Status: n/a (informative) — acknowledgements.


§7.1 Overview

§7.1 Overview

Spec: §7.1, p. 17 — “The intent of this specification is to specify higher-level abstractions built on top of DDS to achieve first-class request/reply communication.”

Repo: —

Tests: —

Status: n/a (informative) — intent of the specification.


§7.2 General Concepts

§7.2.1 Client: DataWriter for requests, DataReader for replies

Spec: §7.2.1, p. 17 — “Structurally, every client uses a data writer for sending requests and a data reader for receiving replies.”

Repo: crates/rpc/src/requester.rs (Requester, fields request_writer and reply_reader, created in Requester::from_topics); runtime/cpp/include/dds/rpc.hpp (Requester); runtime/java/src/main/java/org/omg/dds/rpc/Requester.java (interface), RequesterImpl.java

Tests: crates/rpc/tests/runtime_e2e.rs::e2e_single_request_response_roundtrip, crates/rpc-rust-e2e/tests/e2e.rs::the_generated_calculator_binding_runs_every_call, crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together, crates/rpc/tests/java_rpc_runtime.rs::the_java_rpc_runtime_and_the_generated_services_run_together

Status: done — all three runtimes hold one writer for requests and one reader for replies. The Java runtime as interfaces: 771f12846807.

§7.2.1 Service: DataReader for requests, DataWriter for replies

Spec: §7.2.1, p. 17 — “Symmetrically, every service uses a data reader for receiving the requests and a data writer for sending the replies.”

Repo: crates/rpc/src/replier.rs (Replier, fields request_reader and reply_writer, created in Replier::from_topics); runtime/cpp/include/dds/rpc.hpp (Replier); runtime/java/src/main/java/org/omg/dds/rpc/Replier.java (interface), ReplierImpl.java

Tests: crates/rpc/src/replier.rs::tests::tick_processes_request_and_writes_reply, crates/rpc-rust-e2e/tests/e2e.rs::the_generated_calculator_binding_runs_every_call, crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together, crates/rpc/tests/java_rpc_runtime.rs::the_java_rpc_runtime_and_the_generated_services_run_together

Status: done — all three runtimes hold one reader for requests and one writer for replies. The Java runtime as interfaces: 771f12846807.

§7.2.1 Replies of other clients are filtered out

Spec: §7.2.1, p. 17 — “To ensure that the client receives a response to a previous call made by itself, a content-based filter is used by the reader at the client-side. This ensures that responses for remote invocations of other clients are filtered.”

Repo: crates/rpc/src/requester.rs::Requester::tick (a reply whose related_request_id matches no outstanding request is discarded); runtime/cpp/include/dds/rpc.hpp (Requester, decode_reply and decode_enhanced_reply: comparison of the GUID in related_request_id with the GUID of the own request writer request_writer_guid_); runtime/java/src/main/java/org/zerodds/ddsrpc/RequesterImpl.java (drain: the same comparison with requestWriterGuid)

Tests: crates/rpc/src/requester.rs::tests::tick_drops_reply_without_matching_request, crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together (section “a reply to another client is filtered out” in crates/rpc/tests/cpp/rpc_runtime_roundtrip.cpp), crates/rpc/tests/java_rpc_runtime.rs::the_java_rpc_runtime_and_the_generated_services_run_together (the same section in crates/rpc/tests/java/RpcRuntimeRoundtrip.java)

Status: done — none of the three runtimes hands a reply to the application that belongs to a request of another client. The filter works in the Requester after the read, not as a ContentFilteredTopic of the DataReader; the specification asks for the effect. C++ and Java: 35aa702e4900.

§7.2.1 Content filter in C++ and Java

Spec: §7.2.1, p. 17 — as above.

Repo: runtime/cpp/include/dds/rpc.hpp (Requester, request_writer_guid_); runtime/java/src/main/java/org/zerodds/ddsrpc/RequesterImpl.java (requestWriterGuid, drain)

Tests: crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together, crates/rpc/tests/java_rpc_runtime.rs::the_java_rpc_runtime_and_the_generated_services_run_together

Status: done — Requester::receive_replies (C++) and drain (Java) discard a reply whose related_request_id carries the GUID of another request writer, before it reaches the application or its error handling. In the Enhanced path the same comparison applies to the related_identity from PID_RELATED_SAMPLE_IDENTITY. 35aa702e4900.

§7.2.1 Several outstanding requests of one client

Spec: §7.2.1, p. 17 — “It is possible for a client to have more than one outstanding request […] As a consequence, each individual request must be correlated with the corresponding reply.”

Repo: crates/rpc/src/requester.rs (Requester::pending, matching in Requester::tick); runtime/cpp/include/dds/rpc.hpp (Requester::pending_, Requester::receive_reply); runtime/java/src/main/java/org/zerodds/ddsrpc/RequesterImpl.java (receiveReply(SampleIdentity))

Tests: crates/rpc/tests/runtime_e2e.rs::e2e_multi_pending_requests_all_get_their_reply, crates/rpc/src/requester.rs::tests::tick_correlates_reply_with_pending_slot, crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together (section “two outstanding requests”), crates/rpc/tests/java_rpc_runtime.rs::the_java_rpc_runtime_and_the_generated_services_run_together (the same section)

Status: done — matching by the SampleIdentity of the request in all three runtimes; a reply is assigned to its request even if the replies arrive in another order.

§7.2.1 A request is identified by its SampleIdentity

Spec: §7.2.1, p. 17 — “Requests, like all samples in the DDS data space, are identified using a unique SampleIdentity defined as a struct composed of GUID_t and a SequenceNumber_t defined in sub clause 7.5.1.1.1 Common Types.”

Repo: crates/rpc/src/common_types.rs::SampleIdentity; crates/rpc/src/requester.rs::Requester::next_request_id; runtime/cpp/include/dds/rpc.hpp (dds::SampleIdentity); runtime/java/src/main/java/org/omg/dds/rpc/SampleIdentity.java

Tests: crates/rpc/src/requester.rs::tests::send_request_async_assigns_unique_sample_ids, crates/rpc/src/common_types.rs::tests::sample_identity_invalid_constant_is_rtps_unknown

Status: done — the type consists of a GUID and a SequenceNumber_t in all three runtimes, and every request receives a unique identity. That this identity is the identity of the sample is the subject of the next item.

§7.2.1 Identity of the request is that of the sample

Spec: §7.2.1, p. 17 — as above.

Repo: Rust: crates/rpc/src/requester.rs::Requester::next_request_id (GUID of the request writer and DataWriter::next_sequence_number, called under send_lock); crates/dcps/src/publisher.rs (DataWriter::next_sequence_number). Java: runtime/java/src/main/java/org/zerodds/ddsrpc/ZeroDdsParticipant.java (nextIdentity asks psm.nextIdentity() of the writer in crates/java-omgdds/java/src/main/java/org/zerodds/pub/DataWriterImpl.java). C++: runtime/cpp/include/dds/rpc/zerodds.hpp (Writer::next_identity asks zerodds_writer_next_sequence_number in crates/zerodds-c-api/src/lib.rs)

Tests: crates/rpc-rust-e2e/tests/e2e.rs::a_live_request_identity_is_the_rtps_identity_of_the_request_writer, crates/java-omgdds/java/src/test/java/org/omg/dds/rpc/ZeroDdsParticipantTest.java::aWriteReturnsItsIdentityAndTheReaderSeesItWithTheRelatedOne, crates/zerodds-c-api/tests/writer_next_sequence_number.rs::the_next_sequence_number_is_the_one_the_next_write_carries

Status: done — Rust and Java carry the identity of the sample in the RequestHeader (Rust 2314c1c5fb58, Java through the PSM binding a2a9a67acb58). In C++, Writer::next_identity returns the sequence number from the writer through zerodds_writer_next_sequence_number (94181922bf32). The program crates/rpc/tests/cpp/real_library_roundtrip.cpp runs the C++ binding (runtime/cpp/include/dds/rpc/zerodds.hpp) against the real C library libzerodds: two runtimes of one domain, a generated client and service of the Enhanced mapping, every call is matched with its reply by the identity of the sample and PID_RELATED_SAMPLE_IDENTITY (test crates/rpc/tests/cpp_rpc_real_library.rs::the_cpp_binding_runs_against_libzerodds, commit 192200b5a2e1; run on the Linux test host, green). The run found a defect, fixed in 90be3edf2d76: ClientEndpoint::bind did not bind the requesters the client sends through to the instance.

§7.2.1 The reply names the identity of the request

Spec: §7.2.1, p. 17 — “When a service implementation sends a reply to a specific remote invocation, it is necessary to identify the original request by providing the sample-identity of the request.”

Repo: crates/rpc/src/replier.rs::Replier::tick (ReplyHeader::new with header.request_id; Enhanced: write_related); runtime/cpp/include/dds/rpc.hpp (Replier::send_reply with related_request_id); runtime/java/src/main/java/org/omg/dds/rpc/Replier.java (sendReply(reply, relatedRequestId))

Tests: crates/rpc/src/replier.rs::tests::tick_processes_request_and_writes_reply, crates/rpc/tests/runtime_e2e.rs::e2e_client_side_request_identity_is_the_one_the_reply_relates_to, crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together (check “related_request_id is the request’s identity”)

Status: done — Rust, C++ and Java write the identity of the request into the reply (Basic: ReplyHeader::related_request_id; Enhanced: PID_RELATED_SAMPLE_IDENTITY). C++ and Java: 58634aa2702a; Enhanced: e305669e2c42, C++ 2bfb2786121b.

§7.2.1 The reply’s own identity

Spec: §7.2.1, p. 17 — “Note that a reply data sample has its own unique message-id (sample identity), which represents the reply message itself and is independent of the request sample-identity.”

Repo: —

Tests: —

Status: n/a (informative) — note on a property of every DDS sample.

§7.2.2 Two styles of language binding

Spec: §7.2.2, p. 18 — “This specification includes a higher-level language binding with function-call style and a lower-level language binding with request/reply style.”

Repo: —

Tests: —

Status: n/a (informative) — overview; the obligation is in §7.2.2.3.

§7.2.2.1 Function-call Style

Spec: §7.2.2.1, p. 18 — “To provide function-call style, a common approach is to generate stubs that serve as client-side proxies for remote operations and skeletons to support service-side implementations.”

Repo: —

Tests: —

Status: n/a (informative) — description; the entities are in §7.11.1.5 and §7.11.2.3.

§7.2.2.2 Request/Reply Style

Spec: §7.2.2.2, p. 18 — “The request/reply style provides a flat interface, such as send_request, receive_request, and send_reply, receive_reply”.

Repo: —

Tests: —

Status: n/a (informative) — description; the operations are in §7.11.1.4 and §7.11.2.2.

§7.2.2.3 Pros and cons of the styles

Spec: §7.2.2.3, p. 19 — comparison of the styles; “It is possible for a client to use function-call style language binding to invoke remote operations on a server that uses request/reply style language binding to implement the service.”

Repo: crates/rpc/src/topic_naming.rs (BindingStyle, ServiceTopicNames: the request/reply style does not take the interface name, §7.4.1); crates/rpc/src/requester.rs, crates/rpc/src/replier.rs (with_instance_style, with_topics_style, with_options)

Tests: crates/rpc/src/requester.rs::tests::request_reply_style_drops_the_interface_segment, crates/rpc/tests/language_binding_agreement.rs::both_readings_of_seven_four_produce_the_same_topic_names, crates/rpc-rust-e2e/tests/e2e.rs::the_generated_calculator_binding_runs_every_call (a Requester in request/reply style calls the generated service in function-call style), crates/rpc/tests/cpp_function_call.rs::the_generated_client_calls_the_generated_service, crates/rpc/tests/java_rpc_runtime.rs::the_generated_function_call_client_calls_the_generated_service (the same direction in C++ and Java), crates/rpc-rust-e2e/tests/evolution_styles_discovery.rs::a_basic_function_call_client_calls_a_request_reply_service (generated client in function-call style against a Replier in request/reply style)

Status: done — the topic names follow §7.4.1 for both styles (6834e51fdfef), the entities in request/reply style talk to the generated service in function-call style, and the generated client in function-call style (CalculatorClient) calls a Replier with BindingStyle::RequestReply on topic names set to equal values (414e077c527d). The test checks the names demo_Calculator_Service_Request and demo_Calculator_Service_Reply and two calls of add.

§7.2.2.3 Both styles are supported

Spec: §7.2.2.3, p. 19 — “In light of the above observation, a conforming implementation to this specification shall support both styles of language binding.”

Repo: Rust: crates/rpc/src/requester.rs, crates/rpc/src/replier.rs (request/reply), crates/lang-rules/src/emit/interface_rust.rs (client_impl, dispatcher_impl; function-call). C++: runtime/cpp/include/dds/rpc.hpp (Requester, Replier), crates/lang-rules/src/emit/interface_cpp/calls.rs (client_class, service_class). Java: runtime/java/src/main/java/org/omg/dds/rpc/ (RequesterImpl, ReplierImpl, FunctionCallClient, FunctionCallService), crates/lang-rules/src/emit/interface_java/calls.rs (client_class, service_class)

Tests: crates/rpc/tests/runtime_e2e.rs::e2e_single_request_response_roundtrip, crates/rpc-rust-e2e/tests/e2e.rs::the_generated_calculator_binding_runs_every_call, crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together, crates/rpc/tests/cpp_function_call.rs::the_generated_client_calls_the_generated_service, crates/rpc/tests/java_rpc_runtime.rs::the_java_rpc_runtime_and_the_generated_services_run_together, crates/rpc/tests/java_rpc_runtime.rs::the_generated_function_call_client_calls_the_generated_service

Status: done — both styles run in Rust, C++ and Java. C++ function-call ec3707125a9b, Java function-call c512ee365514.

§7.2.2.3 Function-call in C++ and Java

Spec: §7.2.2.3, p. 19 — as above.

Repo: crates/lang-rules/src/emit/interface_cpp/calls.rs (client_class, service_class; <I>Client derives from dds::rpc::ClientEndpoint, <I>Service from dds::rpc::Service, which dds::rpc::Server::add accepts); runtime/cpp/include/dds/rpc.hpp (Service, Server); crates/lang-rules/src/emit/interface_java/calls.rs (client_class, service_class: <I>ClientImpl, <I>ServiceImpl); runtime/java/src/main/java/org/omg/dds/rpc/FunctionCallClient.java, FunctionCallService.java

Tests: crates/rpc/tests/cpp_function_call.rs::the_generated_client_calls_the_generated_service, crates/rpc/tests/cpp_enhanced_function_call.rs::the_generated_enhanced_client_calls_the_generated_enhanced_service, crates/rpc/tests/java_rpc_runtime.rs::the_generated_function_call_client_calls_the_generated_service

Status: done — the generated client calls through a Requester, the generated service answers through a Replier; in C++ Server::add accepts the service. C++: ec3707125a9b, Java: c512ee365514, Enhanced in C++ 45ead22cc2b9 and in Java 2ea77f7dad8a.

§7.2.3 Identity retrievable at requester and service

Spec: §7.2.3, p. 19 — “Request-reply correlation requires an ability to retrieve the sample identity (GUID, SN) at both the requester and service side.”

Repo: crates/rpc/src/requester.rs::Requester::send_request_async (returns the SampleIdentity); crates/rpc/src/replier.rs (Replier::receive_requests returns PendingRequest::identity; AsyncReplierHandler receives the identity); runtime/cpp/include/dds/rpc.hpp (WriteSample::identity, Sample::identity); runtime/java/src/main/java/org/omg/dds/rpc/Sample.java (identity())

Tests: crates/rpc/tests/runtime_e2e.rs::e2e_client_side_request_identity_is_the_one_the_reply_relates_to, crates/rpc/src/replier.rs::tests::receive_requests_and_send_reply_expose_the_identity, crates/rpc/src/replier.rs::tests::dispatch_async_hands_the_replier_and_the_identity_to_the_listener

Status: done — the identity is retrievable at the requester and at the service. The synchronous ReplierHandler::handle of the Rust runtime receives only the value of the request; receive_requests and the asynchronous handler supply the identity (c5af5c7c138e).

§7.2.3 Explicit and implicit propagation

Spec: §7.2.3, p. 20 — “Explicit sample-identity implies that the request-id is visible in the top-level data type for the DDS topic. Implicit sample-identity, on the other hand, implies that the request sample-identity is communicated via extensibility mechanisms supported by the DDS-RTPS protocol. Specifically using the inlineQoS sub-message element.”

Repo: —

Tests: —

Status: n/a (informative) — terms; the obligations are in §7.8.1 and §7.8.2.

§7.2.3 APIs for the request-id at client and service

Spec: §7.2.3, p. 20 — “In both cases, the specification provides APIs to get the request-id at the client side and get/set the request-id at the service side.”

Repo: crates/rpc/src/requester.rs::Requester::send_request_async; crates/rpc/src/replier.rs (Replier::receive_requests, Replier::send_reply with RequestIdentity); runtime/cpp/include/dds/rpc.hpp (Replier::receive_requests, Replier::send_reply with related_request_id); runtime/java/src/main/java/org/omg/dds/rpc/Replier.java (receiveRequests, sendReply(reply, relatedRequestId))

Tests: crates/rpc/tests/runtime_e2e.rs::e2e_client_side_request_identity_is_the_one_the_reply_relates_to, crates/rpc/src/replier.rs::tests::receive_requests_and_send_reply_expose_the_identity, crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together, crates/rpc/tests/java_rpc_runtime.rs::the_java_rpc_runtime_and_the_generated_services_run_together

Status: done — reading at the client and reading and setting at the service in Rust, C++ and Java. Rust at the service: c5af5c7c138e.

§7.2.4 Basic: no extension of DDS and RTPS, explicit request-id

Spec: §7.2.4, p. 20 — “The Basic service mapping enables RPC over DDS functionality without any extensions to the [DDS] and [DDS-RTPS] specifications. It uses explicit request-id for correlation.”

Repo: crates/rpc/src/wire_codec.rs (encode_request_frame, encode_reply_frame); crates/rpc/src/requester.rs::Requester::tick; runtime/cpp/include/dds/rpc.hpp (RequestHeader::request_id, ReplyHeader::related_request_id); runtime/java/src/main/java/org/omg/dds/rpc/HeaderCodec.java

Tests: crates/rpc/src/requester.rs::tests::tick_correlates_reply_with_pending_slot, crates/rpc/tests/cpp_rpc_runtime.rs::the_two_headers_take_the_same_octets_in_both_columns, crates/rpc/tests/java_rpc_runtime.rs::the_two_headers_take_the_same_octets_in_both_columns

Status: done — all three runtimes carry the request-id in the header of the sample and need no extension of DDS or RTPS for the Basic mapping. C++ and Java fill requestId with the identity of the writer: 58634aa2702a. Whether in C++ this identity is the one assigned by the writer is the subject of the item “Identity of the request is that of the sample”.

§7.2.4 Enhanced: overview and table

Spec: §7.2.4, p. 20 — “The Enhanced service mapping uses implicit request-id for correlation, allows use of the additional data-types defined in DDS-XTypes, uses DDS-XTypes for type-compatibility checking, and provides more robust service discovery.” Plus the table of the features of both mappings.

Repo: —

Tests: —

Status: n/a (informative) — overview; every feature is listed individually in §7.4.3, §7.5.1.2, §7.6.2 and §7.8.2.

§7.2.5 Same mapping on both sides

Spec: §7.2.5, p. 20 — “Basic and Enhanced Service Mappings can be mixed in an application but for any given service both client and the service side must use the same service mapping.”

Repo: —

Tests: —

Status: n/a (informative) — constraint on the application. The ZeroDDS runtimes know Basic and Enhanced (RpcMapping::Basic and RpcMapping::Enhanced in crates/rpc/src/endpoint_options.rs); the application chooses per service.

§7.2.5 Mapping independent of the style

Spec: §7.2.5, p. 20 — “The Basic and Enhanced Service mappings are independent of the language binding style. For instance, it is possible for clients and service implementations to communicate using different language binding styles as long as their service mappings match.”

Repo: crates/rpc/src/requester.rs, crates/rpc/src/replier.rs, runtime/cpp/include/dds/rpc.hpp, runtime/java/src/main/java/org/omg/dds/rpc/ (every runtime has Basic and Enhanced for both styles; RpcMapping or ServiceMapping selects the mapping, BindingStyle the style)

Tests: crates/rpc-rust-e2e/tests/e2e.rs::the_generated_calculator_binding_runs_every_call, crates/rpc-rust-e2e/tests/enhanced_e2e.rs::an_enhanced_call_is_answered_through_the_related_sample_identity, crates/rpc/tests/cpp_enhanced_function_call.rs::the_generated_enhanced_client_calls_the_generated_enhanced_service, crates/rpc-rust-e2e/tests/evolution_styles_discovery.rs::a_basic_function_call_client_calls_a_request_reply_service, crates/rpc-rust-e2e/tests/evolution_styles_discovery.rs::an_enhanced_function_call_client_calls_a_request_reply_service

Status: done — both mappings run with both styles. Basic: a Requester in request/reply style against the generated service in function-call style (tests in the item §7.2.2.3 “Pros and cons of the styles”) and the other way round a_basic_function_call_client_calls_a_request_reply_service. Enhanced: an_enhanced_function_call_client_calls_a_request_reply_service (client in function-call style, Replier in request/reply style, topic names set to equal values enh_Calc_Service_Request and enh_Calc_Service_Reply; 414e077c527d).


§7.3 Service Definition

§7.3 Two kinds of service definition

Spec: §7.3, p. 21 — “A service definition is provided using the following two alternatives. a) Interface […] b) A Pair of Types […] This specification uses OMG Interface Definition Language (IDL) or Java 1.5 as a concrete syntax to define services with either of the mechanisms above.”

Repo: —

Tests: —

Status: n/a (informative) — overview; the kinds are listed in §7.3.1 to §7.3.2.2 individually.

§7.3.1 Service Definition in IDL

Spec: §7.3.1, p. 21 — “This specification uses the interface definition syntax specified in [IDL]. Additionally, annotations are supported to provide extra information. […] this specification provides synchronous and asynchronous invocation capabilities only at the language binding level.”

Repo: —

Tests: —

Status: n/a (informative) — classification; the productions are in §7.3.1.1, the synchronous and asynchronous calls in §7.11.1.1.2.

§7.3.1.1 Production (1) specification

Spec: §7.3.1.1, p. 21 — “(1) ::= +”; Design Rationale, p. 22: “Modified to remove the CORBA-specific import statement.”

Repo: crates/idl-parse/src/decl.rs (sequence of definitions; parse_import); crates/rpc/src/service_mapping.rs::lower_service (refuses import with RpcError::OutsideServiceGrammar); crates/lang-rules/src/adapter/interface.rs::services (reject_outside_service_grammar refuses import with InterfaceError::OutsideServiceGrammar)

Tests: crates/idl-lower/tests/conformance.rs::the_xtypes_specifications_own_idl_lowers_completely, crates/rpc/src/service_mapping.rs::tests::an_import_directive_is_outside_the_service_grammar, crates/lang-rules/tests/interface_bindings.rs::the_seam_refuses_an_import_directive

Status: done — a sequence of definitions is read. lower_service (the service model in Rust) refuses import (1627b386b569), and the generator path refuses import as well (c9f99bb02dd5). The front end crates/idl-parse still reads full IDL 4.2 and accepts import; the refusal applies at the seam to the services, not in the parser.

§7.3.1.1 Production (2) definition

Spec: §7.3.1.1, p. 21 — “(2) ::= ”;” | “;” | “;” | “;” | “;” | “;” | “;” “; Design Rationale, p. 22: removes <type_id_dcl>, <type_prefix_dcl>, <event>, <component>, <home_dcl>; adds annotation declarations.

Repo: crates/idl-parse/src/decl.rs (definitions, @annotation declaration, suffix annotations //@); crates/rpc/src/service_mapping.rs::lower_service (refuses typeid, typeprefix and component)

Tests: crates/rpc/src/annotations.rs::tests::dds_request_and_reply_topics_lower_and_resolve, crates/idl-parse/tests/parse.rs::a_suffix_annotation_reaches_the_tree_as_an_annotation, crates/rpc/src/service_mapping.rs::tests::a_typeid_directive_is_outside_the_service_grammar, crates/rpc/src/service_mapping.rs::tests::a_typeprefix_directive_is_outside_the_service_grammar, crates/rpc/src/service_mapping.rs::tests::a_component_declaration_is_outside_the_service_grammar, crates/lang-rules/tests/interface_bindings.rs::the_seam_refuses_typeid_and_typeprefix_directives, crates/lang-rules/tests/interface_bindings.rs::the_seam_refuses_a_component, crates/lang-rules/tests/interface_bindings.rs::the_seam_refuses_an_import_directive

Status: done — the remaining alternatives and annotation declarations are read. lower_service refuses typeid, typeprefix and component (1627b386b569, 009e7a5ef119); crates/lang-rules/src/adapter/interface.rs::service makes the same check for the generators (c9f99bb02dd5).

§7.3.1.1 Production (7) interface_header with annotation

Spec: §7.3.1.1, p. 21 — “(7) ::= [ ] “interface” [ ]”.

Repo: crates/idl-parse/src/decl.rs; annotations on the interface read in crates/rpc/src/annotations.rs::lower_rpc_annotations

Tests: crates/rpc/src/annotations.rs::tests::dds_request_and_reply_topics_lower_and_resolve, crates/rpc/src/service_mapping.rs::tests::every_base_interface_becomes_a_topic_alias, crates/rpc/src/service_mapping.rs::tests::a_local_interface_is_outside_the_service_grammar

Status: done — annotations on the interface are read (c9f21d8f9a8e); lower_service refuses forms other than interface (local, abstract, component) (009e7a5ef119).

§7.3.1.1 Production (9) export

Spec: §7.3.1.1, p. 22 — “(9) ::= “;” | “;””; Design Rationale, p. 23: “This production also removes the rules that allow embedding declarations of types, constants, and exceptions within an interface.”

Repo: crates/lang-rules/src/adapter/interface.rs::service (operations and attributes); crates/rpc/src/service_mapping.rs::lower_service (operations and attributes; constants, types and exceptions in the interface give RpcError::OutsideServiceGrammar)

Tests: crates/lang-rules/tests/interface_bindings.rs::the_seam_reads_every_part_of_an_interface, crates/rpc/src/service_mapping.rs::tests::a_nested_declaration_is_outside_the_service_grammar, crates/rpc/src/service_mapping.rs::tests::a_nested_type_declaration_is_outside_the_service_grammar, crates/lang-rules/tests/interface_bindings.rs::the_seam_refuses_a_type_in_an_interface_body, crates/lang-rules/tests/interface_bindings.rs::the_seam_refuses_a_constant_in_an_interface_body, crates/lang-rules/tests/interface_bindings.rs::the_seam_refuses_an_exception_in_an_interface_body

Status: done — in lower_service a member other than an attribute or an operation is an error (1627b386b569). crates/lang-rules/src/adapter/interface.rs::service refuses a constant, a type and an exception in the interface with InterfaceError::OutsideServiceGrammar (c9f99bb02dd5).

§7.3.1.1 Production (42) type_dcl with annotation

Spec: §7.3.1.1, p. 22 — “(42) ::= [ ] “typedef” | [ ] | | | “native” | ”.

Repo: crates/idl-parse/src/decl.rs; crates/idl-lower/src/annotation.rs

Tests: crates/idl-parse/tests/parse.rs::annotations_bind_to_the_declaration_that_follows, crates/idl-lower/tests/annotations.rs::an_alias_supplies_a_default_that_the_use_site_overrides

Status: done — annotations on type declarations are read (b0a9331d9221).

§7.3.1.1 Production (87) op_dcl

Spec: §7.3.1.1, p. 22 — “(87) ::= [ ] [ ]”; Design Rationale, p. 23: “Removed the CORBA-specific “oneway” modifier and the “context” expressions.”

Repo: crates/idl-parse/src/decl.rs; crates/rpc/src/service_mapping.rs::lower_method (refuses oneway, @oneway and context)

Tests: crates/rpc/src/service_mapping.rs::tests::the_oneway_keyword_is_outside_the_service_grammar, crates/rpc/src/service_mapping.rs::tests::the_oneway_annotation_is_outside_the_service_grammar, crates/rpc/src/service_mapping.rs::tests::a_context_clause_is_outside_the_service_grammar, crates/lang-rules/tests/interface_bindings.rs::the_seam_refuses_a_oneway_operation, crates/lang-rules/tests/interface_bindings.rs::the_seam_refuses_the_oneway_annotation, crates/lang-rules/tests/interface_bindings.rs::the_seam_refuses_a_context_clause

Status: done — lower_service refuses the word oneway, @oneway and a context clause with RpcError::OutsideServiceGrammar (1627b386b569, cc78028ceb52). The reader of the generators (crates/lang-rules/src/adapter/interface.rs::one_operation) refuses them with InterfaceError::OutsideServiceGrammar (c9f99bb02dd5); the sources of the generator tests and of crates/rpc-rust-e2e no longer contain oneway (83ead28f9c52). The field Operation::oneway and the oneway branches in emit/interface_{cpp,java,rust,typescript}.rs and in crates/webdds-bridge are removed (31247aca290). The design rationale of the production names the removal (“Removed the CORBA-specific “oneway” modifier and the “context” expressions.”); §7.3.2 keeps @oneway for Java sources only (java_service_def). The IDL @oneway is refused as well: the rationale row speaks of the IDL grammar, and a Java-only annotation has no mapping in the topic types.

§7.3.1.1 Production (91) param_dcl with annotation

Spec: §7.3.1.1, p. 22 — “(91) ::= [ ] ”.

Repo: crates/rpc/src/service_mapping.rs::lower_method (annotations on the parameter, override_direction)

Tests: crates/rpc/src/service_mapping.rs::tests::param_annotation_in_overrides_declared_direction, crates/idl-lower/tests/conformance.rs::the_xtypes_specifications_own_idl_lowers_completely

Status: done — annotations on a parameter change its direction (52a3f267a6d7).

§7.3.1.1 Production (104) readonly_attr_spec with annotation

Spec: §7.3.1.1, p. 22 — “(104) ::= [ ] “readonly” “attribute” ”.

Repo: crates/idl-parse/src/decl.rs

Tests: crates/idl-lower/tests/conformance.rs::the_xtypes_specifications_own_idl_lowers_completely (@key readonly attribute long version; in dds_xtypes.idl)

Status: done — the front end reads the annotation before readonly attribute (784e1e121a5f).

§7.3.1.1 Production (106) attr_spec with annotation

Spec: §7.3.1.1, p. 22 — “(106) ::= [ ] “attribute” ”.

Repo: crates/idl-parse/src/decl.rs

Tests: crates/idl-parse/tests/parse.rs::annotations_bind_to_the_declaration_that_follows, crates/idl-parse/tests/parse.rs::an_annotation_precedes_a_writable_attribute

Status: done — the front end reads annotations before declarations in general; the test with @id(1) attribute long x; (without readonly) shows the annotation as the first child of the AttributeDecl node (eb2c0e0f8f47).

§7.3.1.1 Production (106) attr_spec: test with a writable attribute

Spec: §7.3.1.1, p. 22 — as above.

Repo: crates/idl-parse/src/decl.rs

Tests: crates/idl-parse/tests/parse.rs::an_annotation_precedes_a_writable_attribute

Status: done — an_annotation_precedes_a_writable_attribute parses interface I { @id(1) attribute long x; }; without a diagnostic and checks that the node contains no readonly (eb2c0e0f8f47).

§7.3.1.1 — constructs outside the grammar of the mapping

Spec: §7.3.1.1, p. 21–23 — “The IDL 3.5 grammar shall be modified with the productions shown below.” The Design Rationale names what is dropped: import, <type_id_dcl>, <type_prefix_dcl>, <event>, <component>, <home_dcl>, declarations of types, constants and exceptions in an interface, oneway, context.

Repo: crates/rpc/src/service_mapping.rs::lower_service and lower_method (RpcError::OutsideServiceGrammar in crates/rpc/src/error.rs for import, typeid/typeprefix, component/home/local/abstract, type, constant and exception declarations in the interface, oneway, @oneway, context); crates/idl-lower/src/lower.rs and crates/ast/src/facet/corba.rs (repository_directives for typeid and typeprefix)

Tests: crates/rpc/src/service_mapping.rs::tests::the_oneway_keyword_is_outside_the_service_grammar, crates/rpc/src/service_mapping.rs::tests::the_oneway_annotation_is_outside_the_service_grammar, crates/rpc/src/service_mapping.rs::tests::a_context_clause_is_outside_the_service_grammar, crates/rpc/src/service_mapping.rs::tests::a_nested_declaration_is_outside_the_service_grammar, crates/rpc/src/service_mapping.rs::tests::a_nested_type_declaration_is_outside_the_service_grammar, crates/rpc/src/service_mapping.rs::tests::an_import_directive_is_outside_the_service_grammar, crates/rpc/src/service_mapping.rs::tests::a_typeid_directive_is_outside_the_service_grammar, crates/rpc/src/service_mapping.rs::tests::a_typeprefix_directive_is_outside_the_service_grammar, crates/rpc/src/service_mapping.rs::tests::a_component_declaration_is_outside_the_service_grammar, crates/rpc/src/service_mapping.rs::tests::a_local_interface_is_outside_the_service_grammar, crates/lang-rules/tests/interface_bindings.rs::the_seam_refuses_a_oneway_operation, crates/lang-rules/tests/interface_bindings.rs::the_seam_refuses_a_context_clause, crates/lang-rules/tests/interface_bindings.rs::the_seam_refuses_a_type_in_an_interface_body, crates/lang-rules/tests/interface_bindings.rs::the_seam_refuses_a_constant_in_an_interface_body, crates/lang-rules/tests/interface_bindings.rs::the_seam_refuses_an_exception_in_an_interface_body, crates/lang-rules/tests/interface_bindings.rs::the_seam_refuses_an_import_directive, crates/lang-rules/tests/interface_bindings.rs::the_seam_refuses_typeid_and_typeprefix_directives, crates/lang-rules/tests/interface_bindings.rs::the_seam_refuses_an_abstract_interface, crates/lang-rules/tests/interface_bindings.rs::the_seam_refuses_a_component, crates/lang-rules/tests/interface_bindings.rs::a_local_interface_is_refused_by_the_seam

Status: done — the service model in Rust (lower_service) refuses the removed constructs with RpcError::OutsideServiceGrammar (1627b386b569, 009e7a5ef119). The reader of the generators, crates/lang-rules/src/adapter/interface.rs::service and services (used by idlc generate), makes the same check with InterfaceError::OutsideServiceGrammar (c9f99bb02dd5); a_local_interface_is_refused_by_the_seam also shows that cpp_interface_items and java_interface_items fail for a local interface. The front end (crates/idl-parse) reads full IDL 4.2 and has no profile of the grammar of §7.3.1.1; the refusal sits in lower_service and in the reader of the generators.

§7.3.1.1 Annotations of the Basic mapping do not stay in the result

Spec: §7.3.1.1, p. 23 — “The Basic Service Mapping uses annotations only for interface declarations and not on regular type declarations. These interface annotations are resolved in the mapping such that the resulting IDL used by DDS does not have annotations.”

Repo: crates/lang-rules/src/emit/interface_cpp.rs::declare (the synthesised types are structures without annotation)

Tests: crates/lang-rules/tests/interface_bindings.rs::cpp_declares_the_topic_types_of_seven_five

Status: done — commit ad892a10764a.

§7.3.1.2 XTypes type system in signatures (Enhanced)

Spec: §7.3.1.2, p. 23 — “The Enhanced Service Mapping allows use of the full type-system defined in the DDS-XTypes specification in the declaration of interface attributes, operation parameters, and return values. […] extends the IDL productions defined in the Basic Service Mapping with all the productions […] in sub clause 7.3.1.12.1 (New Productions) of the DDS-XTypes specification.”

Repo: crates/idl-parse/, crates/idl-lower/ (IDL 4.2 with the types of XTypes 1.3)

Tests: crates/idl-lower/tests/conformance.rs::the_xtypes_specifications_own_idl_lowers_completely

Status: done — commit 784e1e121a5f.

§7.3.1.2 Modified productions of XTypes, as in Basic

Spec: §7.3.1.2, p. 23 — “In addition, the Enhanced Service Mapping also uses all the modified productions defined in sub clause 7.3.1.12.2 (Modified Productions) of the [DDS-Xtypes] specification with the exception of the production for , which shall remain, as defined for the Basic Service Mapping.”

Repo: crates/idl-parse/src/decl.rs; crates/rpc/src/service_mapping.rs::lower_service

Tests: crates/idl-lower/tests/conformance.rs::the_xtypes_specifications_own_idl_lowers_completely, crates/rpc/src/service_mapping.rs::tests::a_nested_declaration_is_outside_the_service_grammar, crates/lang-rules/tests/interface_bindings.rs::the_seam_refuses_a_type_in_an_interface_body, crates/lang-rules/tests/interface_bindings.rs::the_seam_refuses_a_constant_in_an_interface_body

Status: done — the front end reads the modified productions of XTypes. <definition> stays that of the Basic mapping for the service model in Rust (lower_service, 1627b386b569) and for the reader of the generators in crates/lang-rules (c9f99bb02dd5); the front end itself reads IDL 4.2 (item “§7.3.1.1 — constructs outside the grammar of the mapping” above).

§7.3.1.3 Example of an Interface in IDL

Spec: §7.3.1.3, p. 23–24 — example robot::RobotControl (“Non-normative”).

Repo: —

Tests: —

Status: n/a (informative) — example.

§7.3.1.4 Pair of types with @RPCRequestType and @RPCReplyType

Spec: §7.3.1.4, p. 24 — “A service definition may simply include a pair of types, which may be the same. The request and reply types shall be marked as such using the @RPCRequestType and @RPCReplyType annotations.”

Repo: crates/rpc/src/type_pair.rs::lower_type_pairs (reads the pairs out of a model; TypePairService); crates/rpc/src/annotations.rs::lower_single (RpcAnnotation::RpcRequestType, RpcAnnotation::RpcReplyType); crates/ast/src/node/annotation.rs (BUILTIN_ANNOTATIONS, the annotations need no declaration)

Tests: crates/rpc/src/type_pair.rs::tests::a_marked_pair_with_headers_is_a_basic_service, crates/rpc/src/type_pair.rs::tests::one_type_may_be_both_halves, crates/rpc/src/annotations.rs::tests::the_pair_annotations_lower_and_resolve, crates/rpc/src/annotations.rs::tests::the_spec_annotations_need_no_declaration

Status: done — 6c7f585a36ee (predefined annotations), 1e28b13546c1 (lower_type_pairs; @RPCRequest and @RPCReply, which the spec does not know, removed).

§7.3.1.4 Evaluation of the pair of types in IDL

Spec: §7.3.1.4, p. 24 — as above.

Repo: crates/rpc/src/type_pair.rs::lower_type_pairs; crates/lang-rules/src/emit/type_pair_rust.rs, crates/lang-rules/src/emit/type_pair_cpp.rs, crates/lang-rules/src/emit/type_pair_java.rs (generated binding over the endpoints, has_pair_types)

Tests: crates/lang-rules/tests/type_pair_rust.rs::a_pair_with_headers_gets_the_header_traits_and_the_endpoints, crates/lang-rules/tests/type_pair_rust.rs::the_service_name_is_read_from_either_annotation_and_can_be_given_at_run_time, crates/lang-rules/tests/type_pair_cpp.rs::a_pair_with_headers_gets_traits_and_support, crates/lang-rules/tests/type_pair_cpp.rs::the_service_name_is_run_time_then_annotation_then_default, crates/lang-rules/tests/type_pair_java.rs::the_generated_pair_declares_the_support_and_uses_the_runtimes_headers, crates/rpc/src/type_pair.rs::tests::the_service_name_comes_from_either_annotation_on_either_type

Status: done — lower_type_pairs turns a pair of marked types into a service (1e28b13546c1). The generators produce a binding for it: Rust d9446301d9b1, C++ 83d80ac9bf48 and 35a69aa60d98, Java f46b42ca8b3a (runtime) and 639d549b4bfd (generator). The service name comes from @service or @DDSService on either type or at run time (f641beefbe78).

§7.3.1.4 Only structures as types of the pair

Spec: §7.3.1.4, p. 24 — “Only struct types shall be marked as request/reply types.”

Repo: crates/rpc/src/type_pair.rs::lower_type_pairs (RpcError::InvalidTypePair for a marked type that is not a structure)

Tests: crates/rpc/src/type_pair.rs::tests::a_marked_type_that_is_not_a_struct_is_refused, crates/lang-rules/tests/type_pair_rust.rs::a_marked_type_that_is_not_a_struct_is_refused

Status: done — 1e28b13546c1.

§7.3.1.4 Basic: member header in the pair of types

Spec: §7.3.1.4, p. 24 — “In the Basic Service Mapping, the types annotated as @RPCRequestType shall have a member named header of type dds::rpc::RequestHeader and the types annotated as @RPCReplyType shall have a member named header of type dds::rpc::RequestHeader.”

Repo: crates/rpc/src/type_pair.rs::lower_type_pairs (header_type; request type: dds::rpc::RequestHeader; reply type: dds::rpc::ReplyHeader, switchable to dds::rpc::RequestHeader with TypePairOptions::reply_header)

Tests: crates/rpc/src/type_pair.rs::tests::a_marked_pair_with_headers_is_a_basic_service, crates/rpc/src/type_pair.rs::tests::a_header_of_the_wrong_type_is_refused, crates/rpc/src/type_pair.rs::tests::a_header_in_only_one_type_is_refused, crates/rpc/src/type_pair.rs::tests::the_reply_header_type_is_a_setting

Status: done — 1e28b13546c1. For the reply type the sentence of the spec names dds::rpc::RequestHeader; §7.5.1.1.1 defines ReplyHeader, and RequestHeader has no related_request_id. The default is ReplyHeader; the wording of the sentence can be selected with TypePairOptions::reply_header.

§7.3.1.4 Enhanced: no annotations, no special members

Spec: §7.3.1.4, p. 24 — “When using the Enhanced Service Mapping, the annotations are not necessary and the special data members must not be defined.”

Repo: crates/rpc/src/type_pair.rs::lower_type_pairs (PairMapping::Enhanced for a pair with no header member in either type)

Tests: crates/rpc/src/type_pair.rs::tests::a_marked_pair_without_headers_is_an_enhanced_service, crates/lang-rules/tests/type_pair_rust.rs::a_pair_without_headers_is_the_enhanced_mapping, crates/lang-rules/tests/type_pair_cpp.rs::a_pair_without_headers_is_the_enhanced_mapping, crates/lang-rules/tests/type_pair_java.rs::the_enhanced_pair_has_no_header_and_selects_the_enhanced_mapping, crates/rpc/src/type_pair.rs::tests::a_header_in_only_one_type_is_refused

Status: done — 1e28b13546c1. A pair with no header member is Enhanced; a header in only one type is refused. The model recognises a pair only by the annotations; types without annotation form no pair, and the spec names no other criterion.

§7.3.2 Java: InterfaceDeclaration

Spec: §7.3.2, p. 24 — “Conforming implementations shall support the syntax generated by the following modified productions from the Java grammar. […] InterfaceDeclaration: NormalInterfaceDeclaration”; Design Rationale, p. 25: “Removed annotation type declaration.”

Repo: crates/rpc/src/java_service_def.rs::parse

Tests: crates/rpc/src/java_service_def.rs::tests::the_example_of_seven_three_two_one_parses, crates/rpc/src/java_service_def.rs::tests::the_removed_productions_are_refused

Status: done — ad892a10764a.

§7.3.2 Java: NormalInterfaceDeclaration

Spec: §7.3.2, p. 24 — “NormalInterfaceDeclaration: interface Identifier [extends TypeList] InterfaceBody”; Design Rationale, p. 25: “Removed generic type parameters.”

Repo: crates/rpc/src/java_service_def.rs (Cursor::interface)

Tests: crates/rpc/src/java_service_def.rs::tests::the_extends_list_survives, crates/rpc/src/java_service_def.rs::tests::the_removed_productions_are_refused

Status: done — ad892a10764a.

§7.3.2 Java: InterfaceBody

Spec: §7.3.2, p. 24 — “InterfaceBody: { InterfaceBodyDeclaration {InterfaceBodyDeclaration} }”; Design Rationale, p. 25: “At least one method must be present in an interface.”

Repo: crates/rpc/src/java_service_def.rs (Cursor::interface)

Tests: crates/rpc/src/java_service_def.rs::tests::an_empty_interface_body_is_refused, crates/rpc/src/java_service_def.rs::tests::the_example_of_seven_three_two_one_parses

Status: done — ad892a10764a.

§7.3.2 Java: InterfaceMemberDecl

Spec: §7.3.2, p. 24 — “InterfaceMemberDecl: InterfaceMethodOrFieldDecl void Identifier VoidInterfaceMethodDeclaratorRest InterfaceDeclaration ClassDeclaration”; Design Rationale, p. 25: “Removed generic method declaration.”

Repo: crates/rpc/src/java_service_def.rs (Cursor::interface, Cursor::method)

Tests: crates/rpc/src/java_service_def.rs::tests::a_return_type_and_a_void_are_told_apart, crates/rpc/src/java_service_def.rs::tests::a_nested_declaration_is_kept, crates/rpc/src/java_service_def.rs::tests::a_field_in_an_interface_body_is_a_constant

Status: done — methods, void methods and nested declarations are read. A field in the interface body is read by Cursor::interface as a constant (JavaInterface::constants), also with dimensions and several declarators; a field without a value is refused with RpcError::JavaSyntax (29381ca02054).

§7.3.2 Java: NormalClassDeclaration

Spec: §7.3.2, p. 24 — “NormalClassDeclaration: class Identifier [extends Type] [implements TypeList] ClassBody”; Design Rationale, p. 25: “Removed generic type parameters.”

Repo: crates/rpc/src/java_service_def.rs (Cursor::class)

Tests: crates/rpc/src/java_service_def.rs::tests::the_example_of_seven_three_two_one_parses, crates/rpc/src/java_service_def.rs::tests::the_removed_productions_are_refused, crates/rpc/src/java_service_def.rs::tests::the_implements_list_of_a_class_survives

Status: done — class, extends, implements (JavaClass::implements) and the refusal of generics are tested (29381ca02054).

§7.3.2 Java: ClassBody

Spec: §7.3.2, p. 24–25 — “ClassBody: { ClassBodyDeclaration {ClassBodyDeclaration} }”; Design Rationale, p. 25: “At least one data member must be defined in the class body.”

Repo: crates/rpc/src/java_service_def.rs (Cursor::class)

Tests: crates/rpc/src/java_service_def.rs::tests::an_empty_class_body_is_refused, crates/rpc/src/java_service_def.rs::tests::the_pair_of_types_of_seven_three_two_two_is_found

Status: done — ad892a10764a.

§7.3.2 Java: ClassBodyDeclaration

Spec: §7.3.2, p. 25 — “ClassBodyDeclaration: ; {Modifier} MemberDecl”; Design Rationale, p. 25: “Removed Java’s static block support.”

Repo: crates/rpc/src/java_service_def.rs (Cursor::class, Cursor::modifiers)

Tests: crates/rpc/src/java_service_def.rs::tests::the_removed_productions_are_refused, crates/rpc/src/java_service_def.rs::tests::the_pair_of_types_of_seven_three_two_two_is_found

Status: done — ad892a10764a.

§7.3.2 Java: MemberDecl

Spec: §7.3.2, p. 25 — “MemberDecl: MethodOrFieldDecl”; Design Rationale, p. 25: “This specification shall support data member declarations inside a Java class.”

Repo: crates/rpc/src/java_service_def.rs (Cursor::class, JavaClass::fields)

Tests: crates/rpc/src/java_service_def.rs::tests::the_pair_of_types_of_seven_three_two_two_is_found, crates/rpc/src/java_service_def.rs::tests::the_removed_productions_are_refused

Status: done — ad892a10764a.

§7.3.2 Java: MethodOrFieldRest

Spec: §7.3.2, p. 25 — “MethodOrFieldRest: VariableDeclaratorRest”; Design Rationale, p. 25: “Removed method declarator.”

Repo: crates/rpc/src/java_service_def.rs (Cursor::class)

Tests: crates/rpc/src/java_service_def.rs::tests::the_pair_of_types_of_seven_three_two_two_is_found, crates/rpc/src/java_service_def.rs::tests::dimensions_after_the_name_belong_to_the_type, crates/rpc/src/java_service_def.rs::tests::an_initialised_member_is_read_without_its_value, crates/rpc/src/java_service_def.rs::tests::several_declarators_share_one_type, crates/rpc/src/java_service_def.rs::tests::a_field_does_not_make_a_method_acceptable_in_a_class

Status: done — a field with and without initialisation, several declarators (int a, b;) and dimensions after the name (int a[];, added to the dimensions of the type) are read and tested (29381ca02054).

§7.3.2 Java: field in an interface, implements and VariableDeclaratorRest

Spec: §7.3.2, p. 24–25 — as above.

Repo: crates/rpc/src/java_service_def.rs (Cursor::interface, Cursor::class)

Tests: crates/rpc/src/java_service_def.rs::tests::a_field_in_an_interface_body_is_a_constant, crates/rpc/src/java_service_def.rs::tests::dimensions_after_the_name_belong_to_the_type, crates/rpc/src/java_service_def.rs::tests::an_initialised_member_is_read_without_its_value, crates/rpc/src/java_service_def.rs::tests::several_declarators_share_one_type, crates/rpc/src/java_service_def.rs::tests::the_implements_list_of_a_class_survives

Status: done — a field in the interface body is a constant and needs a value; dimensions after the name, initialisation, several declarators and implements are read and tested (29381ca02054).

§7.3.2 Java: @in, @out, @inout

Spec: §7.3.2, p. 25 — “In, out, and inout parameters are specified using the @in, @out and @inout annotations. By default the parameters are read only, and the use of @in is optional.”

Repo: crates/rpc/src/java_service_def.rs::direction_of

Tests: crates/rpc/src/java_service_def.rs::tests::the_direction_annotations_of_seven_three_two_are_read

Status: done — ad892a10764a.

§7.3.2 Java: @oneway

Spec: §7.3.2, p. 25 — “One or more operations may be marked oneway using the @oneway annotation.”

Repo: crates/rpc/src/java_service_def.rs (Cursor::method, JavaMethod::oneway)

Tests: crates/rpc/src/java_service_def.rs::tests::the_oneway_annotation_is_read_and_checked

Status: done — ad892a10764a.

§7.3.2.1 Example of an interface in Java

Spec: §7.3.2.1, p. 26 — example RobotControl (“Non-normative”).

Repo: —

Tests: —

Status: n/a (informative) — example.

§7.3.2.2 Java: pair of types with @RPCRequestType and @RPCReplyType

Spec: §7.3.2.2, p. 26 — “A service definition may simply include a pair of types, which may be the same. The request and reply types shall be marked as such using the @RPCRequestType and @RPCReplyType annotations.”

Repo: crates/rpc/src/java_service_def.rs::request_reply_pair

Tests: crates/rpc/src/java_service_def.rs::tests::the_pair_of_types_of_seven_three_two_two_is_found, crates/rpc/src/java_service_def.rs::tests::one_class_may_be_both_halves_of_the_pair

Status: done — ad892a10764a.

§7.3.2.2 Java: only classes as types of the pair

Spec: §7.3.2.2, p. 26 — “Only class types shall be marked as request/reply types.”

Repo: crates/rpc/src/java_service_def.rs::request_reply_pair (considers classes only)

Tests: crates/rpc/src/java_service_def.rs::tests::the_pair_of_types_of_seven_three_two_two_is_found, crates/rpc/src/java_service_def.rs::tests::a_marked_interface_is_reported

Status: done — request_reply_pair reports a marked interface, whichever half it is, with RpcError::InvalidTypePair (“only class types”) (29381ca02054).

§7.3.2.2 Java Basic: member header of type dds.rpc.RequestHeader

Spec: §7.3.2.2, p. 26 — “In the Basic Service Mapping, the types annotated as @RPCRequestType shall have a member named header of type dds.rpc.RequestHeader and the types annotated as @RPCReplyType shall have a member named header of type dds.rpc.RequestHeader.”

Repo: crates/rpc/src/java_service_def.rs::request_reply_pair, JavaClass::has_header_member

Tests: crates/rpc/src/java_service_def.rs::tests::the_type_of_the_header_member_is_checked, crates/rpc/src/java_service_def.rs::tests::a_header_in_only_one_class_is_reported

Status: done — request_reply_pair checks the type of header (dds.rpc.RequestHeader for the request type, dds.rpc.ReplyHeader for the reply type, switchable to RequestHeader with TypePairOptions::reply_header) and reports a header in one class only (29381ca02054).

§7.3.2.2 — checks of the pair in Java

Spec: §7.3.2.2, p. 26 — as the two items above.

Repo: crates/rpc/src/java_service_def.rs::request_reply_pair

Tests: crates/rpc/src/java_service_def.rs::tests::a_marked_interface_is_reported, crates/rpc/src/java_service_def.rs::tests::the_type_of_the_header_member_is_checked, crates/rpc/src/java_service_def.rs::tests::a_header_in_only_one_class_is_reported, crates/rpc/src/java_service_def.rs::tests::an_incomplete_or_ambiguous_pair_is_reported, crates/rpc/src/java_service_def.rs::tests::no_marked_class_is_no_pair

Status: done — a marked interface, a wrong type of header, a header in one class only, a missing half and two classes of the same half give RpcError::InvalidTypePair, as crates/rpc/src/type_pair.rs does for IDL (29381ca02054). With no marked class there is no pair and no error.

§7.3.2.2 Java Enhanced: no annotations, no special members

Spec: §7.3.2.2, p. 26 — “When using the Enhanced Service Mapping, the annotations are not necessary and the special data members must not be defined.”

Repo: crates/rpc/src/java_service_def.rs::request_reply_pair (JavaTypePair::mapping, PairMapping)

Tests: crates/rpc/src/java_service_def.rs::tests::a_pair_without_headers_is_an_enhanced_pair, crates/rpc/src/java_service_def.rs::tests::a_header_in_only_one_class_is_reported

Status: done — request_reply_pair decides as PairMapping in crates/rpc/src/type_pair.rs does: header in both classes is Basic, in none Enhanced, in one an error (29381ca02054). The Java binding for a pair from IDL (crates/lang-rules/src/emit/type_pair_java.rs, ServiceMapping.ENHANCED) is independent of this.


§7.4 Mapping Service Specification to DDS Topics

§7.4.1 from interface, service name and suffix

Spec: §7.4.1, p. 26 — “ ::= “” “” [ “Request” | “Reply” ] | ”.

Repo: crates/rpc/src/topic_naming.rs (compose_topic_name, ServiceTopicNames::synthesize); crates/lang-rules/src/adapter/interface.rs::Service::request_topic_name

Tests: crates/rpc/src/topic_naming.rs::tests::the_default_name_carries_the_service_segment, crates/rpc/src/service_mapping.rs::tests::calculator_service_with_in_params_lowers

Status: done — 4f3b0f132d8a.

§7.4.1 as a name given by the user

Spec: §7.4.1, p. 26 — “Topic name is either a user-defined string literal or a composite string consisting and .”

Repo: crates/rpc/src/topic_naming.rs::ServiceTopicNames::one (whole name from the annotation)

Tests: crates/rpc/src/topic_naming.rs::tests::an_annotation_gives_the_whole_name_and_no_alias, crates/rpc/tests/runtime_e2e.rs::e2e_annotated_whole_topic_name_replaces_the_default_dds_rpc_1_0_section_7_4_2_2

Status: done — 4f3b0f132d8a (names), 77bb7cba7e6d (Requester and Replier take the name from the annotation).

§7.4.1 with default “Service”

Spec: §7.4.1, p. 26–27 — “ ::= “Service” | […] The non-terminal may be user-supplied. When it is not, it defaults to “Service.””

Repo: crates/rpc/src/topic_naming.rs::DEFAULT_SERVICE_NAME; crates/rpc/src/service_mapping.rs::lower_service

Tests: crates/rpc/src/service_mapping.rs::tests::without_the_annotation_the_service_segment_is_the_default, crates/rpc/src/topic_naming.rs::tests::service_topic_names_pair

Status: done — 4f3b0f132d8a.

§7.4.1

Spec: §7.4.1, p. 26–27 — “ ::= 1+$ […] a regular expression that includes alphanumeric characters (a-zA-Z0-9), underscore and space.”

Repo: crates/rpc/src/topic_naming.rs::validate_user_def_alpha_num

Tests: crates/rpc/src/topic_naming.rs::tests::the_published_character_set_admits_a_space_and_a_leading_digit, crates/rpc/src/topic_naming.rs::tests::everything_outside_the_set_is_refused

Status: done — 4f3b0f132d8a. ### §7.4.1 fully qualified

Spec: §7.4.1, p. 26 — “The non-terminal represents the fully-qualified name of the interface, which is captured automatically for interface-based service definitions. A fully qualified interface-name includes concatenation of module names separates by underscores followed by the name of the interface.”

Repo: crates/rpc/src/topic_naming.rs::qualified_interface_name; crates/rpc/src/service_mapping.rs (qualified_name_of); crates/lang-rules/src/adapter/interface.rs::qualified_interface_name

Tests: crates/rpc/src/topic_naming.rs::tests::the_interface_segment_is_the_fully_qualified_name, crates/rpc/src/service_mapping.rs::tests::the_module_chain_reaches_the_topic_name

Status: done — code and tests exist. Commit 4f3b0f132d8a (the topic name is <interface>_<service>_Request).

§7.4.1 Specified with the suffixes Request and Reply

Spec: §7.4.1, p. 27 — “If the is specified by the user, “Request” and “Reply” topic suffixes are used automatically.”

Repo: crates/rpc/src/topic_naming.rs::ServiceTopicNames::one (step 3); in IDL through @service(name = "…") (IDL 4.2), read in crates/rpc/src/annotations.rs::lower_service_annotation

Tests: crates/rpc/src/topic_naming.rs::tests::a_user_supplied_service_name_replaces_only_that_segment, crates/rpc/src/service_mapping.rs::tests::the_service_annotation_supplies_the_service_segment_only

Status: done — code and tests exist. Commits 4f3b0f132d8a (composition of the names), 52a3f267a6d7 (reading @service).

§7.4.1 Java: from @DDSService

Spec: §7.4.1, pp. 26–27 — as above: the user supplies <service_name>; <interface_name> is taken from the interface.

Repo: crates/rpc/src/java_service_def.rs (JavaInterface::service_name, JavaServiceDef::service_name, JavaServiceDef::topic_names); crates/lang-rules/src/emit/interface_java.rs (the generated Support class sets interfaceName and annotatedServiceName)

Tests: crates/rpc/src/java_service_def.rs::tests::the_service_annotation_overrides_the_interface_name, crates/rpc/tests/java/FunctionCallRoundtrip.java (the check on TopicNames.of(named); run by crates/rpc/tests/java_rpc_runtime.rs)

Status: done — @DDSService(name = "…") supplies <service_name>; <interface_name> stays the interface name: Calculator_Arithmetic_Request. Without a name, Service applies. Commits b7f5da73ca28 (Rust reader), 53ae2ab01af5 (the generated Java Support class names the interface for a run-time service name).

§7.4.1 Precedence of specified topic names over the service name

Spec: §7.4.1, p. 27 — “When and user-defined topic names are both provided by the user, the user-defined topic names take precedence.”

Repo: crates/rpc/src/topic_naming.rs::ServiceTopicNames::one; C++: runtime/cpp/include/dds/rpc/core.hpp::dds::rpc::synthesize_topic_names; Java: runtime/java/src/main/java/org/omg/dds/rpc/TopicNames.java::resolve

Tests: crates/lang-rules/tests/interface_bindings.rs::cpp_carries_the_topic_names_of_seven_four, crates/rpc/src/topic_naming.rs::tests::the_run_time_specification_beats_the_annotation, crates/rpc/tests/cpp/rpc_runtime_roundtrip.cpp::check_class_form (run by crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together)

Status: done — within one layer the topic name wins (annotation before @service; run-time suffix before run-time service name). For a run-time service name next to a topic name from an annotation, the code follows §7.4.2.3 (p. 28: run time before annotation); there p. 27 and p. 28 contradict each other. Commit 4f3b0f132d8a.

§7.4.1 Request/reply style: no

Spec: §7.4.1, p. 27 — “For the request-reply style language binding, and the following underscore shall not be captured automatically.”

Repo: crates/rpc/src/topic_naming.rs (BindingStyle, compose_topic_name); crates/rpc/src/endpoint.rs::RpcEndpointBuilder::binding_style; Rust runtime in the next item; C++: runtime/cpp/include/dds/rpc/core.hpp::dds::rpc::synthesize_topic_names (BindingStyle::RequestReply); Java: runtime/java/src/main/java/org/omg/dds/rpc/TopicNames.java::resolve (an empty interfaceName omits the segment)

Tests: crates/rpc/src/topic_naming.rs::tests::the_request_reply_style_drops_the_interface_segment, crates/rpc/src/endpoint.rs::tests::the_binding_style_decides_the_topic_name, crates/rpc/tests/cpp/rpc_runtime_roundtrip.cpp::check_class_form (run by crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together)

Status: done — composition of the names in Rust and C++ with a test. For Java the case exists in the code of TopicNames.resolve; there is no test with an empty interfaceName. Commits 4f3b0f132d8a (composition), 2ea2abb7d843 (C++), 35156b3406a3 (Java).

§7.4.1 Rust runtime: topic names in the request/reply style

Spec: §7.4.1, p. 27 — as above.

Repo: crates/rpc/src/requester.rs (Requester::with_instance_style, with_topics_style, with_options); crates/rpc/src/replier.rs (Replier::with_instance_style, with_topics_style, with_options)

Tests: crates/rpc/src/requester.rs::tests::request_reply_style_drops_the_interface_segment, crates/rpc/src/replier.rs::tests::request_reply_style_drops_the_interface_segment

Status: done — with_instance and with_topics form the function-call style; the *_style variants take the style and omit the <interface_name> segment. The tests check the names on the Requester and on the Replier. Commits 6834e51fdfef (composition), 32972ee16bdd (test on the Replier).

§7.4.2 Basic: one request and one reply topic per interface

Spec: §7.4.2, p. 27 — “The Basic Service mapping maps every interface to a request topic and a reply topic.”

Repo: crates/rpc/src/codegen.rs::build_basic_pair; crates/lang-rules/src/emit/interface_rust.rs (client_impl; one Requester per interface)

Tests: crates/rpc/src/codegen.rs::tests::basic_pair_topic_names, crates/rpc-rust-e2e/tests/e2e.rs::the_generated_calculator_binding_runs_every_call

Status: done — code and tests exist. Commits b5224bd70dbb (build_basic_pair), 026f15d1df46 (test with the generated binding).

§7.4.2 Three mechanisms, same names on both sides

Spec: §7.4.2, p. 27 — “It provides three alternative mechanisms to specify the names of the topics. It is possible to use different mechanism at the client and server sides. However, to ensure successful end-point matching, the topic names must match.”

Repo: —

Tests: —

Status: n/a (informative) — overview and a requirement on the application; the mechanisms are in §7.4.2.1 to §7.4.2.3.

§7.4.2 Basic: own pair of topics per interface of the hierarchy

Spec: §7.4.2, p. 27 — “In case of an interface inheritance hierarchy, including multiple inheritance, each interface in the hierarchy shall be mapped to its own pair of request and reply topics.”

Repo: crates/lang-rules/src/emit/interface_rust.rs (client_impl: one field with the base’s client per base; one dispatcher per level); crates/lang-rules/src/emit/interface_cpp.rs::support_class (names per interface)

Tests: crates/rpc-rust-e2e/tests/e2e.rs::a_derived_client_reaches_an_inherited_operation_through_its_base_field

Status: done — code and test exist. Commit 026f15d1df46.

§7.4.2.1 Default Topic Names

Spec: §7.4.2.1, p. 27 — “The default topic names are synthesized using the rules defined in sub clause 7.4.1 Rules for Synthesizing DDS Topic Names.”

Repo: crates/rpc/src/topic_naming.rs::ServiceTopicNames::new; crates/rpc/src/service_mapping.rs::ServiceDef::topic_names; crates/lang-rules/src/emit/interface_cpp.rs::support_class

Tests: crates/rpc/src/topic_naming.rs::tests::service_topic_names_pair, crates/lang-rules/tests/interface_bindings.rs::cpp_carries_the_topic_names_of_seven_four

Status: done — code and tests exist. Commit 4f3b0f132d8a.

§7.4.2.2 @DDSRequestTopic and @DDSReplyTopic on interfaces

Spec: §7.4.2.2, p. 27 — “Interfaces and the request/reply types may be annotated to specify the names of the request and reply topics. @DDSRequestTopic and @DDSReplyTopic annotations are pre-defined for this purpose.”

Repo: crates/rpc/src/annotations.rs::lower_single; crates/rpc/src/service_mapping.rs::ServiceDef (request_topic, reply_topic); crates/lang-rules/src/adapter/interface.rs::service (annotation_string)

Tests: crates/rpc/src/annotations.rs::tests::dds_request_and_reply_topics_lower_and_resolve, crates/rpc/src/service_mapping.rs::tests::the_topic_annotations_and_the_run_time_layer_have_their_order, crates/lang-rules/tests/interface_bindings.rs::cpp_carries_the_topic_names_of_seven_four

Status: done — read on interfaces; on the types of a pair and as predefined annotations in the two following items. Commit 4f3b0f132d8a.

§7.4.2.2 Annotations on the types of a pair

Spec: §7.4.2.2, p. 27 — as above.

Repo: crates/rpc/src/type_pair.rs::lower_type_pairs (reads @DDSRequestTopic and @DDSReplyTopic on the types, §7.3.1.4)

Tests: crates/rpc/src/type_pair.rs::tests::the_topic_annotations_on_the_types_name_the_topics

Status: done — code and test exist. Commit 1e28b13546c1.

§7.4.2.2 DDSRequestTopic and DDSReplyTopic predefined

Spec: §7.4.2.2, p. 27 — “module dds { module rpc { @Annotation local interface DDSRequestTopic { attribute String name; }; @Annotation local interface DDSReplyTopic { attribute String name; }; }; };”

Repo: crates/ast/src/node/annotation.rs (BUILTIN_ANNOTATIONS: DDSRequestTopic, DDSReplyTopic); crates/rpc/src/annotations.rs::lower_single

Tests: crates/rpc/src/annotations.rs::tests::the_spec_annotations_need_no_declaration, crates/rpc/src/annotations.rs::tests::dds_request_and_reply_topics_lower_and_resolve

Status: done — a file uses both annotations without declaring them. They are built-in annotations of the front end; the IDL declaration of the spec (module dds { module rpc { @Annotation local interface … } }) is not offered as IDL text. They are read by the last part of the name; besides name = "…" the short form without a name is accepted. A use with the full name (@dds::rpc::DDSRequestTopic) was not checked. Commit 6c7f585a36ee.

§7.4.2.2 XTypes not required in the implementation

Spec: §7.4.2.2, p. 27 — “Note that support for [DDS-XTypes] in the underlying DDS implementation is not required to interpret the annotations. These annotations simply control the generated DDS wrapper code.”

Repo: —

Tests: —

Status: n/a (informative) — note.

§7.4.2.3 Topic names at run time through the params classes

Spec: §7.4.2.3, p. 28 — “DDS Topic names may also be specified at run-time. The ServiceParams, ClientParams, RequesterParams, and ReplierParams classes […] provide functions to specify the service name and the topic name suffix. When used as such, the rules defined in 7.4.1 Rules for Synthesizing DDS Topic Names apply.”

Repo: crates/rpc/src/topic_naming.rs::TopicNameOverrides (service_name, request_suffix, reply_suffix), passed through AnnotatedTopics to Requester::with_topics and Replier::with_topics; crates/rpc/src/endpoint.rs::RpcEndpointBuilder::topic_name_overrides; C++ and Java in the next item

Tests: crates/rpc/src/topic_naming.rs::tests::a_user_supplied_suffix_replaces_the_whole_tail, crates/rpc/src/endpoint.rs::tests::the_run_time_service_name_reaches_the_endpoints

Status: done — Rust: run-time service name and suffix with the rules of §7.4.1; C++ and Java in the item “Params classes in C++ and Java”. Commits 4f3b0f132d8a, 77bb7cba7e6d.

§7.4.2.3 Params classes in C++ and Java

Spec: §7.4.2.3, p. 28 — as above.

Repo: C++: runtime/cpp/include/dds/rpc.hpp (EndpointParams with service_name, request_topic_name_suffix, reply_topic_name_suffix; RequesterParams, ReplierParams, ServiceParams, ClientParams; synthesize_topic_names); Java: runtime/java/src/main/java/org/omg/dds/rpc/ (RequesterParams, ReplierParams with serviceName, requestTopicNameSuffix, replyTopicNameSuffix; TopicNames)

Tests: crates/rpc/tests/cpp/rpc_runtime_roundtrip.cpp::check_class_form (run by crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together), crates/rpc/tests/java/FunctionCallRoundtrip.java (TopicNames.of(named); run by crates/rpc/tests/java_rpc_runtime.rs)

Status: done — the params classes take the service name and the suffix and compose the names by §7.4.1. ServiceParams and ClientParams appear in the spec only in the C++ binding (§7.11.1.5); Java has none. Commits 2ea2abb7d843 (C++), 35156b3406a3 (Java).

§7.4.2.3 Precedence: run time, annotation, default

Spec: §7.4.2.3, p. 28 — “When more than one method of specifying topic names is used, the run-time specification shall take precedence over the IDL annotations and the default mechanism in that order.”

Repo: crates/rpc/src/topic_naming.rs::ServiceTopicNames::one; C++: runtime/cpp/include/dds/rpc/core.hpp::dds::rpc::synthesize_topic_names; Java: runtime/java/src/main/java/org/omg/dds/rpc/TopicNames.java::resolve

Tests: crates/rpc/src/topic_naming.rs::tests::the_run_time_specification_beats_the_annotation, crates/rpc/src/service_mapping.rs::tests::the_topic_annotations_and_the_run_time_layer_have_their_order, crates/rpc/tests/cpp/rpc_runtime_roundtrip.cpp::check_class_form (run by crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together)

Status: done — code and tests exist. Commits 4f3b0f132d8a, 2ea2abb7d843 (C++), 35156b3406a3 (Java).

§7.4.3 Enhanced: aliases announced in discovery

Spec: §7.4.3, p. 28 — “To support single and multiple inheritance of interfaces, the Enhanced Service mapping introduces a notion called “topic aliases.” […] Topic aliases are announced during the endpoint discovery protocol using either of the PublicationBuiltinTopicDataExt and SubscriptionBuiltinTopicDataExt structures described in 7.6.2.1”.

Repo: crates/rpc/src/topic_naming.rs::ServiceTopicNames::aliases; crates/rpc/src/requester.rs and crates/rpc/src/replier.rs (with_options put topic_aliases into RpcDiscoveryExt); crates/rpc/src/endpoint.rs::RpcEndpointBuilder; crates/rtps/src/publication_data.rs (topic_aliases, codec of PID_TOPIC_ALIASES); crates/dcps (matching by alias, functions in crates/discovery); C++: runtime/cpp/include/dds/rpc.hpp (topic_aliases) and runtime/cpp/include/dds/rpc/zerodds.hpp

Tests: crates/rpc/src/endpoint.rs::tests::the_parent_interfaces_are_announced_as_topic_aliases, crates/rpc/src/topic_naming.rs::tests::the_request_reply_style_has_no_aliases_for_the_bases_either, crates/rpc-rust-e2e/tests/evolution_styles_discovery.rs::the_runtime_announces_aliases_the_instance_name_and_the_related_keys, crates/rtps/src/publication_data.rs::tests::rpc_discovery_pids_roundtrip, crates/rtps/src/publication_data.rs::tests::a_discovery_string_beyond_the_bound_is_refused, crates/dcps/tests/topic_alias_matching.rs::a_reader_on_an_alias_matches_the_writer_over_the_wire, crates/rpc/tests/cpp/rpc_runtime_roundtrip.cpp (check request_reader.aliases.size() == 1; run by crates/rpc/tests/cpp_rpc_runtime.rs)

Status: done — Rust, C++ and Java announce the aliases, crates/dcps matches by alias, and crates/rtps refuses an alias beyond string<256>. In Java, ReplierParams.parents (and RequesterParams.parents) set the base interfaces; TopicNames forms one alias per base from them (9993349aff89, test RpcInheritanceTest.java::specOperations, RpcDiscoveryTest.java::aTopicCorrespondsByNameOrByAlias). A client of a base reaches a derived service through the alias match although the type names of the request and reply types differ: the topics of the Enhanced mapping now announce the TypeInformation of their types (lang-rules builds the CompleteTypeObject of Request, Reply, In, Out, Result, the exceptions and RemoteExceptionCode_t: a2bc3b857739; DomainParticipant::create_topic_with_type_information in crates/dcps; Requester and Replier call it when the generated options carry the objects). Test: crates/rpc-rust-e2e/tests/enhanced_type_information.rs::base_and_derived::a_base_client_calls_a_derived_service (two participants; green on the Linux test host; without the objects the same call ends with ServiceNotMatched, measured with a control run). The Rust runtime carries the type information; C++ and Java announce none (see the items on §7.5.1.2.6 and §7.7.2.5). Commits e305669e2c42 (Rust), 17a3aef74360 (C++), bdf9ab1e6caa (match by alias in crates/dcps), ae5fededca89 (bound in crates/rtps), 32972ee16bdd and 414e077c527d (tests).

§7.4.3 Enhanced: Java announces the aliases of the params

Spec: §7.4.3, p. 28 — “To support single and multiple inheritance of interfaces, the Enhanced Service mapping introduces a notion called “topic aliases.” […] Topic aliases are announced during the endpoint discovery protocol using either of the PublicationBuiltinTopicDataExt and SubscriptionBuiltinTopicDataExt structures described in 7.6.2.1”.

Repo: —

Tests: crates/rpc-rust-e2e/tests/java_peer.rs::a_java_client_calls_a_rust_service, crates/rpc-rust-e2e/tests/java_peer.rs::a_rust_client_calls_a_java_service, crates/rpc-rust-e2e/tests/java_peer.rs::a_java_client_of_the_base_calls_a_rust_service_of_the_derived_interface, crates/rpc-rust-e2e/tests/java_peer.rs::a_rust_client_of_the_base_calls_a_java_service_of_the_derived_interface

Status: done — RequesterParams.parents and ReplierParams.parents take the base interfaces; TopicNames.resolve makes one alias for each base (not under the request-reply style and not for a whole topic name, as in Rust), and RequesterImpl and ReplierImpl report them through DataWriter.announce and DataReader.announce (ZeroDdsParticipant → DataWriterImpl.setRpcDiscovery, PID 0x0082; 9993349aff89, f65fb3965b5e). Tests: crates/rpc/tests/java/RpcInheritanceTest.java::specOperations (names and aliases), RpcDiscoveryTest.java::theThreeParametersTravelWithTheEndpoint (PID 0x0082 on the wire). The generated Java binding of the Enhanced mapping sets parents for a derived interface (400433a9d00a, checked on CalcSupport with Calc : Base2 in EnhancedRuntimeChecks.support(), c9c4e86a881e). Measured: a Java client against a Rust service and a Rust client against a Java service over RTPS, both with the announcement of the aliases and of the TypeInformation (dbb935492284). The Java PSM matches the endpoints of the Enhanced mapping over the aliases of the peer (RpcDiscovery.topicsCorrespond) and by the assignability of the announced TypeInformation (XTypes 1.3 §7.6.3.4.2; RawTypeSupport.matchesByTypeInformation, org.zerodds.rtps.TypeConsistency, org.zerodds.typelookup.CompleteTypes, 2d0f809c6e2). It fetches objects of the peer with getTypes from the peer’s TypeLookup service; the Java description also carries the MINIMAL objects a Rust peer asks for (9b1608508c5), and a reader of a described type announces ALLOW_TYPE_COERCION (d67a980f80b). Measured over RTPS against Rust peers (Linux test host): a Java client of Base2 calls a Rust service of Derived2, a Rust client of Base2 a Java service of Derived2; both cells failed on 78f243b596f, before the matching by assignability.

§7.4.3 Enhanced: exactly one request and one reply topic per interface

Spec: §7.4.3, p. 28 — “The Enhanced Service Mapping shall map an interface to exactly one request topic and a reply topic. The names of the topics are obtained using the rules defined in 7.4.1 Rules for Synthesizing DDS Topic Names.”

Repo: crates/rpc/src/codegen.rs::build_enhanced_service (request_topic, reply_topic); crates/rpc/src/endpoint_options.rs::RpcMapping::Enhanced; Requester::with_options and Replier::with_options (crates/rpc/src/requester.rs, crates/rpc/src/replier.rs)

Tests: crates/rpc/src/codegen.rs::tests::enhanced_service_has_one_topic_pair, crates/rpc-rust-e2e/tests/enhanced_e2e.rs::an_enhanced_call_is_answered_through_the_related_sample_identity

Status: done — the Enhanced mapping forms one pair of topics per interface; the Rust runtime uses it (RpcMapping::Enhanced). C++ and Java: commits 51bb6973e062 and 2cb2bcbe4eca. Commits 0edbbcf11324 (mapping), e305669e2c42 (Rust runtime).

§7.4.3 Enhanced: aliases per base by §7.4.1

Spec: §7.4.3, p. 28 — “In case of single and multiple inheritance, the request and reply topics shall additionally have topic-aliases, which are obtained using the rules in sub clause 7.4.1 for each parent interface.”

Repo: crates/rpc/src/topic_naming.rs::ServiceTopicNames::aliases; crates/rpc/src/service_mapping.rs::ServiceDef::bases; crates/lang-rules/src/adapter/interface.rs::Service::topic_aliases

Tests: crates/rpc/src/topic_naming.rs::tests::every_parent_interface_contributes_one_alias, crates/rpc/tests/language_binding_agreement.rs::the_published_table_comes_out_of_the_idl

Status: done — aliases are formed for the direct bases; whether “each parent interface” also means bases of bases, the spec does not say. Commit 4f3b0f132d8a.

§7.4.3 Example of the Calculator hierarchy

Spec: §7.4.3, pp. 28–29 — table with topic names and aliases for Calculator : Adder, Subtractor (“Non-normative example”).

Repo: —

Tests: —

Status: n/a (informative) — example.

§7.4.3 Request/reply style: no interface name

Spec: §7.4.3, p. 29 — “For the request-reply style language binding, the interfaces name shall not be annexed automatically.”

Repo: crates/rpc/src/topic_naming.rs::ServiceTopicNames::aliases (no aliases for the request/reply style); C++: runtime/cpp/include/dds/rpc.hpp (topic_aliases)

Tests: crates/rpc/src/topic_naming.rs::tests::the_request_reply_style_drops_the_interface_segment (without bases; alias list empty)

Status: done — the request/reply style forms no name with the interface and no aliases; the Rust runtime takes the style (item at §7.4.1). The test passes no bases. Commits 4f3b0f132d8a, 6834e51fdfef.

§7.4.3.1 Default Topic Names (Enhanced)

Spec: §7.4.3.1, p. 29 — “The default topic names are synthesized as described above.”

Repo: crates/rpc/src/topic_naming.rs::ServiceTopicNames::synthesize; crates/rpc/src/codegen.rs::build_enhanced_service

Tests: crates/rpc/src/codegen.rs::tests::enhanced_service_has_one_topic_pair, crates/rpc/src/topic_naming.rs::tests::the_default_name_carries_the_service_segment

Status: done — code and tests exist. Commits 4f3b0f132d8a, 0edbbcf11324.

§7.4.3.2 Annotations for the names (Enhanced)

Spec: §7.4.3.2, p. 29 — “The same built-in @DDSRequestTopic and @DDSReplyTopic annotations defined in the Basic Service Mapping may be used for this purpose.”

Repo: crates/rpc/src/service_mapping.rs::ServiceDef (request_topic, reply_topic); crates/rpc/src/type_pair.rs::lower_type_pairs

Tests: crates/rpc/src/topic_naming.rs::tests::an_annotation_gives_the_whole_name_and_no_alias, crates/rpc/src/type_pair.rs::tests::the_topic_annotations_on_the_types_name_the_topics

Status: done — the annotations act independently of the mapping (items at §7.4.2.2). Commits 4f3b0f132d8a, 1e28b13546c1.

§7.4.3.3 Topic names at run time (Enhanced)

Spec: §7.4.3.3, p. 29 — same wording as §7.4.2.3, including “the run-time specification shall take precedence over the IDL annotations and the default mechanism in that order.”

Repo: crates/rpc/src/topic_naming.rs::TopicNameOverrides; crates/rpc/src/endpoint.rs::RpcEndpointBuilder::topic_name_overrides; C++ and Java: params classes (item at §7.4.2.3)

Tests: crates/rpc/src/topic_naming.rs::tests::the_run_time_specification_beats_the_annotation, crates/rpc/src/endpoint.rs::tests::the_run_time_service_name_reaches_the_endpoints

Status: done — code and tests exist. Commits 4f3b0f132d8a, 0edbbcf11324.


§7.5 Mapping Service Specification to DDS Topics Types

§7.5 Topic types from the interface definition

Spec: §7.5, p. 30 — “The request and reply DDS Topic types shall be synthesized from the interface definition.”

Repo: crates/rpc/src/codegen.rs::build_basic_pair, crates/rpc/src/codegen.rs::build_enhanced_service; crates/lang-rules/src/emit/interface_cpp.rs::declare; crates/lang-rules/src/emit/interface_java.rs; crates/lang-rules/src/emit/interface_rust.rs::declare

Tests: crates/lang-rules/tests/interface_bindings.rs::cpp_declares_the_topic_types_of_seven_five, crates/rpc/tests/language_binding_agreement.rs::both_readings_of_seven_five_produce_the_same_sample_structure

Status: done — the types are synthesized, and the topics of the Rust runtime carry them under their names (next item). Commits ad892a10764a (generators), e305669e2c42 (Rust runtime).

§7.5 Type and shape of the samples on the wire

Spec: §7.5, p. 30 — as above; §7.5.1.1.6 and §7.5.1.1.7 fix ${interfaceName}_Request and ${interfaceName}_Reply as the topic types.

Repo: crates/rpc/src/requester.rs and crates/rpc/src/replier.rs (create_topic_with_type_name with ${I}_Request and ${I}_Reply; Requester::request_type_name); crates/rpc/src/wire_codec.rs (encode_request_frame: padding to 4 before the Call; ERROR_REPLY_DATA); C++: runtime/cpp/include/dds/rpc.hpp (Requester and Replier pass dds_type_traits<T>::type_name()), runtime/cpp/include/dds/rpc/zerodds.hpp

Tests: crates/rpc-rust-e2e/tests/enhanced_e2e.rs::the_topics_are_announced_with_the_interface_type_names, crates/rpc/src/wire_codec.rs::tests::the_call_union_starts_on_a_4_octet_boundary, crates/rpc/src/wire_codec.rs::tests::the_error_reply_data_is_the_default_case_of_the_union, crates/rpc/tests/cpp/rpc_runtime_roundtrip.cpp (announced type names robot::Calculator_Request and _Reply; run by crates/rpc/tests/cpp_rpc_runtime.rs)

Status: done — the topics announce ${interfaceName}_Request and ${interfaceName}_Reply as type names; a sample is the header, the padding to 4 octets and the encoding of ${I}_Call or ${I}_Return; a reply with an error code carries the default case of the Return union. The Rust runtime writes the octets of these structures through RawBytes; the generated Rust structures ${I}_Request and ${I}_Reply are not the types of a topic of the runtime, and their encoding gives the same octets (column test in the item on the encoding). Commits e305669e2c42 (Rust), 208e7e0b25c3 (C++).

§7.5.1.1 Basic: types for DDS 1.3 without XTypes

Spec: §7.5.1.1, p. 30 — “The Basic Service Mapping maps interfaces to data-types that can be used by DDS version 1.3 compliant implementations, which may lack support for the [DDS-XTypes] specification.”

Repo: crates/lang-rules/src/emit/interface_cpp.rs::declare (structures and unions without XTypes annotations)

Tests: crates/lang-rules/tests/interface_bindings.rs::cpp_declares_the_topic_types_of_seven_five

Status: done — the types use nothing from XTypes; the encoding is classic CDR (next item). Commit ad892a10764a.

§7.5.1.1 Encoding of the samples: classic CDR and XCDR2

Spec: §7.5.1.1, p. 30 — as above.

Repo: crates/rpc/src/endpoint_options.rs (WireEncoding, default Xcdr1; RpcEndpointOptions); crates/lang-rules/src/emit/interface_rust.rs (rpc_layout_key_xcdr1, rpc_layout_key); C++: runtime/cpp/include/dds/rpc.hpp (WireEncoding); Java: runtime/java/src/main/java/org/omg/dds/rpc/WireEncoding.java

Tests: crates/rpc/src/endpoint_options.rs::tests::the_defaults_are_the_spec_readings, crates/rpc-rust-e2e/tests/wire_bytes_match_columns.rs::the_rust_and_cpp_columns_put_eight_octet_members_where_the_same_octets, crates/rpc-rust-e2e/tests/wire_bytes_match_columns.rs::the_rust_and_java_columns_put_eight_octet_members_where_the_same_octets, crates/rpc-rust-e2e/tests/xcdr1_nested.rs::an_appendable_member_has_no_dheader_under_xcdr1, crates/rpc-rust-e2e/tests/xcdr1_nested.rs::xcdr2_frames_the_same_value_differently

Status: done — for the Basic mapping the spec says only “DDS 1.3 without XTypes”. The default in all three runtimes is classic CDR (XCDR1; a writer offers only that representation); XCDR2 is a named setting. The Enhanced mapping is always XCDR2. The columns for Rust, C++ and Java put members of 8 octets at the same places (test), including nested @appendable/@mutable members. Against a foreign peer this was not checked in this audit. Commits c5285c57fad2 (Rust), ec3707125a9b (C++), 80df19b642fc (Java), 87cf9c7d0b26 (nested members), 77ded59f712c (column test).

§7.5.1.1.1 GUID_t, SequenceNumber_t and SampleIdentity

Spec: §7.5.1.1.1, p. 30 — module dds { typedef octet GuidPrefix_t[12]; struct EntityId_t { octet entityKey[3]; octet entityKind; }; struct GUID_t { GuidPrefix_t guidPrefix; EntityId_t entityId; }; struct SequenceNumber_t { long high; unsigned long low; }; struct SampleIdentity { GUID_t writer_guid; SequenceNumber_t sequence_number; }; ...

Repo: crates/rpc/src/common_types.rs::SampleIdentity (GUID as 16 octets, sequence number as high/low on the wire, encode_sample_identity); runtime/cpp/include/dds/rpc.hpp::dds::SampleIdentity and dds::SequenceNumber_t (high, low; member sequence_number); runtime/java/src/main/java/org/omg/dds/rpc/SampleIdentity.java

Tests: crates/rpc/src/common_types.rs::tests::xcdr2_layout_sample_identity_le_is_24_bytes_no_padding, crates/rpc/src/common_types.rs::tests::sample_identity_roundtrip_le, crates/rpc/tests/cpp_rpc_runtime.rs::the_two_headers_take_the_same_octets_in_both_columns

Status: done — the octets agree in Rust, C++ and Java; the C++ dds::SampleIdentity has the member sequence_number of type dds::SequenceNumber_t with high and low. Commit d750a045b9fe.

§7.5.1.1.1 UnknownOperation, UnknownException, UnusedMember

Spec: §7.5.1.1.1, p. 31 — “typedef octet UnknownOperation; typedef octet UnknownException; typedef octet UnusedMember;”

Repo: crates/rpc/src/common_types.rs (UnusedMember, UnknownOperation, UnknownException); runtime/cpp/include/dds/rpc.hpp (UnusedMember, UnknownOperation, UnknownException); runtime/java/src/main/java/org/omg/dds/rpc/ (UnusedMember.java, UnknownOperation.java, UnknownException.java)

Tests: crates/rpc/tests/language_binding_agreement.rs::the_common_types_and_member_names_are_spelled_once

Status: done — code and test exist. Commit ad892a10764a.

§7.5.1.1.1 RemoteExceptionCode_t with six values

Spec: §7.5.1.1.1, p. 31 — “enum RemoteExceptionCode_t { REMOTE_EX_OK, REMOTE_EX_UNSUPPORTED, REMOTE_EX_INVALID_ARGUMENT, REMOTE_EX_OUT_OF_RESOURCES, REMOTE_EX_UNKNOWN_OPERATION, REMOTE_EX_UNKNOWN_EXCEPTION };”

Repo: crates/rpc/src/common_types.rs::RemoteExceptionCode; runtime/cpp/include/dds/rpc/base.hpp::RemoteExceptionCode_t; runtime/java/src/main/java/org/omg/dds/rpc/RemoteExceptionCode.java

Tests: crates/rpc/src/common_types.rs::tests::reply_header_roundtrip_all_codes, crates/rpc/src/common_types.rs::tests::remote_exception_code_six_is_outside_the_spec_enum, crates/rpc/src/language_binding.rs::tests::the_table_of_seven_eleven_one_three_is_the_published_one

Status: done — the six values 0 to 5 in Rust, C++ and Java; a seventh value no longer exists (next item). Commit 2fe2b7cdea14.

§7.5.1.1.1 No additional values in RemoteExceptionCode_t

Spec: §7.5.1.1.1, p. 31 — as above.

Repo: crates/rpc/src/common_types.rs::RemoteExceptionCode::from_u32 (every value above 5 is RpcError::UnknownExceptionCode); runtime/java/src/main/java/org/omg/dds/rpc/RemoteExceptionCode.java::fromWire (throws RemoteUnknownExceptionError)

Tests: crates/rpc/src/common_types.rs::tests::remote_exception_code_six_is_outside_the_spec_enum, crates/rpc/src/language_binding.rs::tests::the_exception_table_covers_the_six_spec_codes

Status: done — UnknownInterface = 6 is removed; the value 6 from the wire is rejected. Commit 2fe2b7cdea14.

§7.5.1.1.1 InstanceName as string<255>

Spec: §7.5.1.1.1, p. 31 — “typedef string<255> InstanceName;”

Repo: crates/rpc/src/common_types.rs::RequestHeader::instance_name, MAX_STRING_LEN (255), RequestHeader::to_cdr_le, encode_string; crates/rpc/src/wire_codec.rs::encode_request_frame

Tests: crates/rpc/src/common_types.rs::tests::request_header_roundtrip_le, crates/rpc/src/common_types.rs::tests::request_header_instance_name_over_255_is_rejected_on_encode, crates/rpc/tests/cpp/rpc_runtime_roundtrip.cpp::main (block “InstanceName of 255 characters”; run by crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together), crates/rpc/tests/java/RpcRuntimeRoundtrip.java::headerCodec (run by crates/rpc/tests/java_rpc_runtime.rs::the_java_rpc_runtime_and_the_generated_services_run_together)

Status: done — Rust rejects a name longer than 255 on encoding, and the decoder accepts at most 256 octets including the NUL. C++ (InvalidArgumentError on encoding, false on decoding) and Java (IllegalArgumentException on encoding, RemoteInvalidArgumentError on decoding, bound counted in octets) hold the same bound. Commits e5f4e895ad1d (Rust), ea817b7746ef (C++), 3f07ca73a620 (Java).

§7.5.1.1.1 Bound 255 of InstanceName in C++ and Java

Spec: §7.5.1.1.1, p. 31 — as above.

Repo: runtime/cpp/include/dds/rpc/core.hpp::dds::rpc::detail::put_string, get_string, INSTANCE_NAME_BOUND; runtime/java/src/main/java/org/omg/dds/rpc/HeaderCodec.java (putString, getString, MAX_INSTANCE_NAME_OCTETS)

Tests: crates/rpc/tests/cpp/rpc_runtime_roundtrip.cpp::main (block “InstanceName of 255 characters”: 255 characters round-trip, 256 are refused on encoding and on decoding; run by crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together), crates/rpc/tests/java/RpcRuntimeRoundtrip.java::headerCodec (255 octets, 256 octets, 128 characters of two octets, length field 257 and above 2^31, missing NUL; run by crates/rpc/tests/java_rpc_runtime.rs::the_java_rpc_runtime_and_the_generated_services_run_together)

Status: done — both runtimes check the bound 255 when encoding and when decoding the RequestHeader. Commits ea817b7746ef (C++), 3f07ca73a620 (Java).

§7.5.1.1.1 RequestHeader

Spec: §7.5.1.1.1, p. 31 — “struct RequestHeader { SampleIndentity_t requestId; InstanceName instanceName; };”

Repo: crates/rpc/src/common_types.rs::RequestHeader; runtime/cpp/include/dds/rpc/base.hpp::RequestHeader; runtime/java/src/main/java/org/omg/dds/rpc/RequestHeader.java

Tests: crates/rpc/src/common_types.rs::tests::request_header_roundtrip_le, crates/rpc/src/common_types.rs::tests::xcdr2_layout_string_includes_nul, crates/rpc/tests/cpp_rpc_runtime.rs::the_two_headers_take_the_same_octets_in_both_columns, crates/rpc/tests/java_rpc_runtime.rs::the_two_headers_take_the_same_octets_in_both_columns

Status: done — layout and octets agree in Rust, C++ and Java. The C++ members are named requestId and instanceName, and both runtimes check the bound 255 of the name (items “§7.5.1.1.1 — member names in C++” and “Bound 255 of InstanceName in C++ and Java”). Commits d750a045b9fe (names), ea817b7746ef (C++), 3f07ca73a620 (Java).

§7.5.1.1.1 ReplyHeader

Spec: §7.5.1.1.1, p. 31 — “struct ReplyHeader { dds::SampleIdentity relatedRequestId; dds::rpc::RemoteExceptionCode_t remoteEx; };”

Repo: crates/rpc/src/common_types.rs::ReplyHeader; runtime/cpp/include/dds/rpc/base.hpp::ReplyHeader; runtime/java/src/main/java/org/omg/dds/rpc/ReplyHeader.java

Tests: crates/rpc/src/common_types.rs::tests::reply_header_roundtrip_all_codes, crates/rpc/src/wire_codec.rs::tests::reply_header_consumed_28_bytes, crates/rpc/tests/cpp_rpc_runtime.rs::the_two_headers_take_the_same_octets_in_both_columns, crates/rpc/tests/java_rpc_runtime.rs::the_two_headers_take_the_same_octets_in_both_columns

Status: done — layout and octets agree in Rust, C++ and Java; the C++ members are named relatedRequestId and remoteEx (item “§7.5.1.1.1 — member names in C++”). Commit d750a045b9fe.

§7.5.1.1.1 — member names in C++

Spec: §7.5.1.1.1, p. 31 — requestId, instanceName, relatedRequestId, remoteEx.

Repo: runtime/cpp/include/dds/rpc.hpp (RequestHeader::requestId, instanceName; ReplyHeader::relatedRequestId, remoteEx; dds::SequenceNumber_t::high, low; dds::SampleIdentity::sequence_number); generated code with the prefix cxx_ for members, enumerators and constants that are reserved words in C++: crates/lang-rules/src/emit/interface_cpp.rs

Tests: crates/rpc/tests/cpp/rpc_runtime_roundtrip.cpp::print_header_octets (sets and reads requestId, instanceName, relatedRequestId, remoteEx, sequence_number.high, sequence_number.low; run by crates/rpc/tests/cpp_rpc_runtime.rs::the_two_headers_take_the_same_octets_in_both_columns), crates/lang-rules/tests/cxx_prefix_members.rs::a_member_that_is_a_reserved_word_is_prefixed_by_cxx

Status: done — the members are named as in the IDL of the spec (requestId, instanceName, relatedRequestId, remoteEx), and sequence_number is a structure member of its own with high and low. The Java runtime uses the IDL names (requestId(), instanceName()). Commit d750a045b9fe.

§7.5.1.1.2 The Hashing Algorithm

Spec: §7.5.1.1.2, pp. 31–32 — “long HASH (string arg) { octet md5_hash [16] ; md5_hash = compute_md5 ( arg ) ; return md5_hash[0] + 256* md5_hash[1] + 256256 md5_hash[2] + 256256256* md5_hash[3]; }”

Repo: crates/rpc/src/rpc_hash.rs::rpc_member_hash; crates/lang-rules/src/adapter/interface.rs::operation_hash

Tests: crates/rpc/src/codegen.rs::tests::the_case_label_is_the_published_hash_arithmetic, crates/rpc/src/rpc_hash.rs::tests::rpc_hash_uses_first_4_bytes_not_last, crates/rpc/src/rpc_hash.rs::tests::rpc_hash_empty_string_is_md5_empty_first_4_bytes

Status: done — the sum can exceed 2^31; ZeroDDS reads the 32 bits as a signed long. The spec declares long HASH and says nothing about overflow. Commits 4085939c47aa (algorithm), 64d55a6c8f94 (labels of the unions).

§7.5.1.1.2 Collisions of *_Hash need not be detected

Spec: §7.5.1.1.2, p. 32 — “Conforming implementation are not required to detect collisions of identifier names of the form *_Hash”.

Repo: —

Tests: —

Status: n/a (informative) — permission. The Basic mapping checks no collision (none in build_call_union); the Enhanced mapping reports RpcError::MemberIdCollision (§7.5.1.2.1.2, another item).

§7.5.1.1.3 Rule 1: get_attribute_ and set_attribute_

Spec: §7.5.1.1.3, p. 32 — “1. Each attribute in an interface maps to a pair of IDL operations. get_attribute_ and set_attribute_ in the same interface.”

Repo: crates/lang-rules/src/adapter/interface.rs::Service::all_operations; crates/rpc/src/service_mapping.rs::lower_service (implied operations per attribute)

Tests: crates/lang-rules/tests/interface_bindings.rs::an_attribute_implies_the_operations_of_seven_five_one_one_three, crates/rpc/src/service_mapping.rs::tests::attributes_lower_into_the_implied_operations_of_seven_five_one_one_three, crates/rpc/src/service_mapping.rs::tests::a_declared_operation_colliding_with_an_implied_one_is_refused, crates/rpc-rust-e2e/tests/e2e.rs::the_generated_calculator_binding_runs_every_call

Status: done — each attribute yields get_attribute_<name> and, unless readonly, set_attribute_<name>, in the generators and in the data model of crates/rpc. Commit 259cf675efdf.

§7.5.1.1.3 Names of the implied operations

Spec: §7.5.1.1.3, p. 32 — as above.

Repo: crates/lang-rules/src/adapter/interface.rs::Service::all_operations (get_attribute_<name>, set_attribute_<name>); crates/rpc/src/service_mapping.rs::lower_service

Tests: crates/lang-rules/tests/interface_bindings.rs::an_attribute_implies_the_operations_of_seven_five_one_one_three, crates/rpc/src/service_mapping.rs::tests::attributes_lower_into_the_implied_operations_of_seven_five_one_one_three

Status: done — the name of the operation enters the labels of the Call and Return unions through HASH (§7.5.1.1.6 rule 5a); with the names get_attribute_<name> and set_attribute_<name> a peer following the spec picks the same labels. Commit 259cf675efdf. ### §7.5.1.1.3 Rule 1: conflict with operations of the same name

Spec: §7.5.1.1.3, p. 32 — “It is illegal to have an interface with an attribute named and user-defined operations named get_attribute_ and set_attribute_.”

Repo: crates/rpc/src/service_mapping.rs::lower_service (check over ServiceDef::all_methods, error RpcError::DuplicateMethod); crates/lang-rules/src/adapter/interface.rs::service (error InterfaceError::DuplicateOperation, also for get_attribute_<name> and set_attribute_<name>)

Tests: crates/rpc/src/service_mapping.rs::tests::a_declared_operation_colliding_with_an_implied_one_is_refused, crates/lang-rules/tests/interface_bindings.rs::the_seam_refuses_an_operation_named_like_an_implied_getter, crates/lang-rules/tests/interface_bindings.rs::the_seam_refuses_an_operation_named_like_an_implied_setter

Status: done — commits 259cf675efdf, c9f99bb02dd5. lower_service and the point adapter::interface::service of the generators for C++, Java and Rust reject an interface that declares an operation with the name of an implied operation. A readonly attribute implies no setter, so the name set_attribute_<name> is allowed there (second test).

§7.5.1.1.3 Rule 1 — check in the generators

Spec: §7.5.1.1.3, p. 32 — as above.

Repo: crates/lang-rules/src/adapter/interface.rs::service (InterfaceError::DuplicateOperation). crates/lang-rules does not call lower_service and does not depend on zerodds-rpc (cycle zerodds-rpc → zerodds-dcps → zerodds-lang-rules); the check therefore stands in adapter::interface::service itself.

Tests: crates/lang-rules/tests/interface_bindings.rs::the_seam_refuses_an_operation_named_like_an_implied_getter, crates/lang-rules/tests/interface_bindings.rs::the_seam_refuses_an_operation_named_like_an_implied_setter, crates/lang-rules/tests/interface_bindings.rs::the_seam_refuses_two_operations_of_one_name

Status: done — commit c9f99bb02dd5. For such an interface the generators receive the error InterfaceError::DuplicateOperation and no longer produce two cases with the same name and label.

§7.5.1.1.3 Rule 2: getter without arguments with the attribute’s type

Spec: §7.5.1.1.3, p. 32 — “2. The return type of the get_attribute_ operation is the same as the attribute’s type. This operation accepts no arguments.”

Repo: crates/lang-rules/src/adapter/interface.rs::Service::all_operations; crates/rpc/src/service_mapping.rs::ServiceDef::all_methods

Tests: crates/lang-rules/tests/interface_bindings.rs::an_attribute_implies_the_operations_of_seven_five_one_one_three, crates/rpc-rust-e2e/tests/e2e.rs::the_generated_calculator_binding_runs_every_call (the generated getter get_attribute_memory() has no argument and returns i32)

Status: done — commit 259cf675efdf.

§7.5.1.1.3 Rule 3: setter void with one argument

Spec: §7.5.1.1.3, p. 32 — “3. The return type of the set_attribute_ operation is void and it accepts an argument of the same type as that of the attribute and the name of the argument is the same as the attribute name.”

Repo: crates/lang-rules/src/adapter/interface.rs::Service::all_operations (parameter with attribute.name); crates/rpc/src/service_mapping.rs::ServiceDef::all_methods

Tests: crates/lang-rules/tests/interface_bindings.rs::an_attribute_implies_the_operations_of_seven_five_one_one_three, crates/rpc-rust-e2e/tests/e2e.rs::the_generated_calculator_binding_runs_every_call, crates/lang-rules/tests/interface_bindings.rs::the_implied_setter_takes_one_argument_named_like_the_attribute, crates/rpc/src/service_mapping.rs::tests::the_implied_setter_takes_one_argument_named_like_the_attribute

Status: done — commits 259cf675efdf, 7036cde62638, 9dbad4cbd573. The first test checks the void return and one argument; the second enforces the type i32 when set_attribute_memory(&self, memory: i32) is compiled. The last two tests check name, direction in and type of the argument against the attribute, and the member of the same name in Calculator_set_attribute_label_In.

§7.5.1.1.3 Rule 3 — name of the argument

Spec: §7.5.1.1.3, p. 32 — as above.

Repo: crates/lang-rules/src/adapter/interface.rs::Service::all_operations (Operation::params); crates/rpc/src/service_mapping.rs::ServiceDef::all_methods (ParamDef::name)

Tests: crates/lang-rules/tests/interface_bindings.rs::the_implied_setter_takes_one_argument_named_like_the_attribute, crates/rpc/src/service_mapping.rs::tests::the_implied_setter_takes_one_argument_named_like_the_attribute

Status: done — commits 7036cde62638, 9dbad4cbd573. Both tests check that the setter’s parameter carries the name of the attribute.

§7.5.1.1.3 Rule 4: getraises

Spec: §7.5.1.1.3, p. 32 — “4. Exception types listed in getraises, if any, are treated as if the get_attribute_ operation has the same set of exceptions listed as raises.”

Repo: crates/lang-rules/src/adapter/interface.rs::Service::all_operations and crates/rpc/src/service_mapping.rs::ServiceDef::all_methods (both set raises: attribute.get_raises.clone()); lower_attribute reads get_raises

Tests: crates/lang-rules/tests/interface_bindings.rs::getraises_and_setraises_become_the_raises_of_the_implied_operations, crates/rpc/src/service_mapping.rs::tests::getraises_and_setraises_become_the_raises_of_the_implied_operations

Status: done — commits 259cf675efdf, 7036cde62638, 9dbad4cbd573. Both tests contain an attribute with getraises and setraises and check that the implied operation get_attribute_<name> lists the exception of getraises in raises.

§7.5.1.1.3 Rule 5: setraises

Spec: §7.5.1.1.3, p. 32 — “5. Exception types listed in setraises, if any, are treated as if the set_attribute_ operation has the same set of exceptions listed as raises.”

Repo: crates/lang-rules/src/adapter/interface.rs::Service::all_operations and crates/rpc/src/service_mapping.rs::ServiceDef::all_methods (both set raises: attribute.set_raises.clone()); lower_attribute reads set_raises

Tests: crates/lang-rules/tests/interface_bindings.rs::getraises_and_setraises_become_the_raises_of_the_implied_operations, crates/rpc/src/service_mapping.rs::tests::getraises_and_setraises_become_the_raises_of_the_implied_operations

Status: done — commits 259cf675efdf, 7036cde62638, 9dbad4cbd573. Both tests contain an attribute with getraises and setraises and check that the implied operation set_attribute_<name> lists the exception of setraises in raises.

§7.5.1.1.3 Rule 4 and 5 — Result union of the implied operations

Spec: §7.5.1.1.3, p. 32 — as above.

Repo: crates/lang-rules/src/emit/interface_cpp.rs::declare (Result union per operation, implied ones included)

Tests: crates/lang-rules/tests/interface_bindings.rs::getraises_and_setraises_become_the_raises_of_the_implied_operations

Status: done — commit 7036cde62638. For Guarded_get_attribute_level_Result the test checks the case notreadable_ex without notwritable_ex, and for Guarded_set_attribute_level_Result the case notwritable_ex without notreadable_ex. The check of all_methods stands in the test crates/rpc/src/service_mapping.rs::tests::getraises_and_setraises_become_the_raises_of_the_implied_operations (commit 9dbad4cbd573).

§7.5.1.1.4 Unqualified names in the rules

Spec: §7.5.1.1.4, p. 32 — “In these rules the token ${interfaceName} shall be replaced with the name of the interface and the token ${operationName}_shall be replaced with the name of the operation. The substituted names are not fully qualified (i.e., any module prefixes shall be removed).”

Repo: crates/lang-rules/src/adapter/interface.rs::in_struct_name; crates/rpc/src/codegen.rs::build_call_union (svc.name, the simple name)

Tests: crates/lang-rules/tests/interface_bindings.rs::cpp_declares_the_topic_types_of_seven_five, crates/rpc/src/codegen.rs::tests::the_result_union_of_seven_five_one_one_five_is_built (interface in module robot, type name Calculator_add_Result)

Status: done — commits 64d55a6c8f94, ad892a10764a.

§7.5.1.1.4 Rule 1: In structure ${interfaceName}_${operationName}_In

Spec: §7.5.1.1.4, p. 32 — “1. Each operation in the interface shall map to an In structure with name “${interfaceName}_${operationName}_In.””

Repo: crates/rpc/src/codegen.rs::build_call_union; crates/lang-rules/src/adapter/interface.rs::in_struct_name

Tests: crates/rpc/src/codegen.rs::tests::basic_request_has_header_and_call_union, crates/lang-rules/tests/interface_bindings.rs::cpp_declares_the_topic_types_of_seven_five

Status: done — commits b5224bd70dbb, ad892a10764a.

§7.5.1.1.4 Rule 2: In structure in the module of the interface

Spec: §7.5.1.1.4, p. 32 — “2. The In structure shall be defined within the same module as the original interface.”

Repo: crates/lang-rules/src/emit/interface_cpp.rs::declare (every declaration with service.module)

Tests: crates/lang-rules/tests/interface_bindings.rs::cpp_declares_the_two_abstract_classes_of_rule_one, crates/lang-rules/tests/interface_bindings.rs::cpp_declares_the_topic_types_of_seven_five, crates/lang-rules/tests/interface_bindings.rs::the_topic_types_and_constants_stand_in_the_module_of_the_interface

Status: done — commits b5224bd70dbb, ad892a10764a, 7036cde62638. The code passes the module of the interface to every declaration. The test creates two modules, plus an exception in a third, and checks for C++ that the declaration stands in the namespace of its interface and neither in the global namespace nor in the namespace of the other module; the Rust binding places the items in the module of their interface. The placement of the Java classes is not checked; the Rust binding has no _Hash constants.

§7.5.1.1.4 Rule 3: in and inout parameters as members

Spec: §7.5.1.1.4, p. 32 — “3. The In structure shall contain as members the in and inout parameters defined in the operation signature.”

Repo: crates/rpc/src/codegen.rs::method_in_members; crates/lang-rules/src/emit/interface_cpp.rs (request_fields)

Tests: crates/rpc/src/codegen.rs::tests::basic_request_in_params_become_case_members, crates/rpc/src/codegen.rs::tests::enhanced_inout_param_is_in_both_structures (the Enhanced mapping calls the same function method_in_members), crates/rpc-rust-e2e/tests/e2e.rs::the_generated_calculator_binding_runs_every_call (swap(inout long v) through the generated Rust binding)

Status: done — commit b5224bd70dbb.

§7.5.1.1.4 Rule 3a: order of the parameters

Spec: §7.5.1.1.4, p. 32 — “a. The members shall appear in the same order as the parameters in the operation, starting from the left.”

Repo: crates/rpc/src/codegen.rs::method_in_members

Tests: crates/rpc/src/codegen.rs::tests::basic_request_in_params_become_case_members (member a, then b)

Status: done — commit b5224bd70dbb.

§7.5.1.1.4 Rule 3b: names of the parameters

Spec: §7.5.1.1.4, p. 32 — “b. The names of the members shall be the same as the formal parameter names.”

Repo: crates/rpc/src/codegen.rs::method_in_members

Tests: crates/rpc/src/codegen.rs::tests::basic_request_in_params_become_case_members

Status: done — commit b5224bd70dbb.

§7.5.1.1.4 Rule 3c: dummy of type UnusedMember

Spec: §7.5.1.1.4, p. 32 — “c. If an operation has no in and inout parameters the resulting structure shall contain a single member of type UnusedMember and name “dummy.””

Repo: crates/rpc/src/codegen.rs::method_in_members (DUMMY_MEMBER); crates/lang-rules/src/emit/interface_cpp.rs (request_fields)

Tests: crates/rpc/src/codegen.rs::tests::an_empty_in_or_out_carries_the_dummy_member, crates/lang-rules/tests/interface_bindings.rs::cpp_declares_the_topic_types_of_seven_five

Status: done — commit 64d55a6c8f94.

§7.5.1.1.5 Out structure and Result union per operation

Spec: §7.5.1.1.5, p. 33 — “Each operation in the interface shall map to an Out structure and a Result union.”

Repo: crates/rpc/src/codegen.rs (method_out_members, build_result_union); crates/lang-rules/src/emit/interface_cpp.rs (reply_fields, result_union_of)

Tests: crates/rpc/src/codegen.rs::tests::the_result_union_of_seven_five_one_one_five_is_built, crates/rpc/src/codegen.rs::tests::basic_reply_excludes_oneway_methods, crates/lang-rules/tests/interface_bindings.rs::cpp_declares_the_topic_types_of_seven_five

Status: done — commits 64d55a6c8f94, ad892a10764a. A oneway operation, which the grammar of §7.3.1.1 does not know (lower_service rejects it), gets neither an Out structure nor a Result union and no case in the Return union (item on production (87)).

§7.5.1.1.5 Out rule 1: name ${interfaceName}_${operationName}_Out

Spec: §7.5.1.1.5, p. 33 — “1. The name of the Out structure shall be “${interfaceName}_${operationName}_Out.””

Repo: crates/rpc/src/codegen.rs::build_result_union (out_type_name); crates/lang-rules/src/adapter/interface.rs::out_struct_name

Tests: crates/rpc/src/codegen.rs::tests::the_result_union_of_seven_five_one_one_five_is_built, crates/rpc/tests/language_binding_agreement.rs::both_readings_of_seven_five_produce_the_same_sample_structure

Status: done — commits 64d55a6c8f94, ad892a10764a.

§7.5.1.1.5 Out rule 2: in the module of the interface

Spec: §7.5.1.1.5, p. 33 — “2. The Out structure shall be defined within the same module as the original interface.”

Repo: crates/lang-rules/src/emit/interface_cpp.rs::declare

Tests: crates/lang-rules/tests/interface_bindings.rs::cpp_declares_the_topic_types_of_seven_five, crates/lang-rules/tests/interface_bindings.rs::the_topic_types_and_constants_stand_in_the_module_of_the_interface

Status: done — commits 64d55a6c8f94, ad892a10764a, 7036cde62638. The code passes the module of the interface. The test creates two modules, plus an exception in a third, and checks for C++ that the declaration stands in the namespace of its interface and neither in the global namespace nor in the namespace of the other module; the Rust binding places the items in the module of their interface. The placement of the Java classes is not checked; the Rust binding has no _Hash constants.

§7.5.1.1.5 Out rule 3: out and inout parameters, plus return_

Spec: §7.5.1.1.5, p. 33 — “3. The Out structure shall contain as members the out and inout parameters defined in the operation signature. In addition it may contain a member named “return_.” a. The Out structure shall include one member for each out and inout parameter in the operation signature.”

Repo: crates/rpc/src/codegen.rs::method_out_members; crates/lang-rules/src/emit/interface_cpp.rs (reply_fields)

Tests: crates/rpc/src/codegen.rs::tests::basic_reply_return_value_is_the_last_member, crates/rpc/src/codegen.rs::tests::enhanced_inout_param_is_in_both_structures (the Enhanced mapping calls the same function method_out_members), crates/rpc-rust-e2e/tests/e2e.rs::the_generated_calculator_binding_runs_every_call

Status: done — commit 64d55a6c8f94.

§7.5.1.1.5 Out rule 3a.i: order of the parameters

Spec: §7.5.1.1.5, p. 33 — “i. The members shall appear in the same order as the parameters in the operation, starting from the left.”

Repo: crates/rpc/src/codegen.rs::method_out_members

Tests: crates/rpc/src/codegen.rs::tests::basic_reply_return_value_is_the_last_member, crates/rpc/src/codegen.rs::tests::basic_out_members_keep_the_order_of_the_parameters, crates/lang-rules/tests/interface_bindings.rs::the_out_structure_keeps_the_order_of_the_parameters

Status: done — commits 64d55a6c8f94, 9dbad4cbd573, 7036cde62638. The code keeps the order of the declaration. The first test has several out and inout parameters; the second checks, with mix(in long a, inout long b, out double c) and mix2(out double c, in long a, inout long b), the order of the members in C++ and Java (return_ last, in parameters not included). The Rust binding has no test of its own for the order of several members.

§7.5.1.1.5 Out rule 3a.i — several parameters

Spec: §7.5.1.1.5, p. 33 — as above.

Repo: crates/rpc/src/codegen.rs::method_out_members; crates/lang-rules/src/emit/interface_cpp.rs (reply_fields)

Tests: crates/rpc/src/codegen.rs::tests::basic_out_members_keep_the_order_of_the_parameters, crates/lang-rules/tests/interface_bindings.rs::the_out_structure_keeps_the_order_of_the_parameters

Status: done — commits 9dbad4cbd573, 7036cde62638. The tests check the order of several out and inout parameters in the Out structure (see the item “Out rule 3a.i: order of the parameters”).

§7.5.1.1.5 Out rule 3a.ii: names of the parameters

Spec: §7.5.1.1.5, p. 33 — “ii. The name of the members shall be the same as the formal parameter names.”

Repo: crates/rpc/src/codegen.rs::method_out_members

Tests: crates/rpc/src/codegen.rs::tests::basic_reply_return_value_is_the_last_member (member wrapped)

Status: done — commit 64d55a6c8f94.

§7.5.1.1.5 Out rule 3b: return_ as the last member

Spec: §7.5.1.1.5, p. 33 — “b. If the operation defines a non-void return value the Out structure shall have its last member named “return_.” The type of the “return_” member shall be the return type of the operation. In the case where the function does not define a return value this member shall not be present.”

Repo: crates/rpc/src/codegen.rs::method_out_members (RETURN_MEMBER)

Tests: crates/rpc/src/codegen.rs::tests::basic_reply_return_value_is_the_last_member, crates/lang-rules/tests/interface_bindings.rs::cpp_declares_the_topic_types_of_seven_five

Status: done — commit 64d55a6c8f94.

§7.5.1.1.5 Out rule 3b: return_N on collision

Spec: §7.5.1.1.5, p. 33 — “If an operation has an out argument named return_ and the operation has a regular return value, the regular return value in the Out structure shall be represented as return_N member of the appropriate type where N is the first integer in the range 1 to 2^31 that avoids the collision.”

Repo: crates/rpc/src/codegen.rs::return_member_name; crates/lang-rules/src/emit/interface_cpp.rs::return_member_name, crates/lang-rules/src/emit/interface_java.rs::return_member_name, crates/lang-rules/src/emit/interface_rust.rs::return_member_name

Tests: crates/rpc/src/codegen.rs::tests::a_colliding_return_member_takes_the_first_free_number, crates/lang-rules/tests/interface_bindings.rs::a_colliding_return_member_is_numbered_in_cpp_and_java, crates/lang-rules/tests/interface_bindings.rs::a_colliding_return_member_is_numbered_in_rust

Status: done — commits 64d55a6c8f94, 7036cde62638. The first test covers return_member_name in crates/rpc; the other two check, with long f(out long return_), the members return_ and return_1 in this order in C++, Java and Rust.

§7.5.1.1.5 Out rule 3b: return_N — generators

Spec: §7.5.1.1.5, p. 33 — as above.

Repo: crates/lang-rules/src/emit/interface_cpp.rs::return_member_name, crates/lang-rules/src/emit/interface_java.rs::return_member_name, crates/lang-rules/src/emit/interface_rust.rs::return_member_name

Tests: crates/lang-rules/tests/interface_bindings.rs::a_colliding_return_member_is_numbered_in_cpp_and_java, crates/lang-rules/tests/interface_bindings.rs::a_colliding_return_member_is_numbered_in_rust

Status: done — commit 7036cde62638. The tests expect return_1 in Odd_f_Out for long f(out long return_) in C++ and Java (text of the declaration) and in Rust (fields of the item).

§7.5.1.1.5 Out rule 3c: dummy without return and without out

Spec: §7.5.1.1.5, p. 33 — “c. If the operation has no return value, no out/inout parameters, the Out structure shall contain a single member named “dummy” of type dds::rpc::UnusedMember.”

Repo: crates/rpc/src/codegen.rs::method_out_members; crates/lang-rules/src/emit/interface_cpp.rs (reply_fields)

Tests: crates/rpc/src/codegen.rs::tests::an_empty_in_or_out_carries_the_dummy_member

Status: done — commit 64d55a6c8f94.

§7.5.1.1.5 Result rule 1: name ${interfaceName}_${operationName}_Result

Spec: §7.5.1.1.5, p. 34 — “1. The Result union name shall be “${interfaceName}}_${operationName}_Result.””

Repo: crates/rpc/src/codegen.rs::build_result_union; crates/lang-rules/src/adapter/interface.rs::result_union_name

Tests: crates/rpc/src/codegen.rs::tests::the_result_union_of_seven_five_one_one_five_is_built

Status: done — commits 64d55a6c8f94, ad892a10764a.

§7.5.1.1.5 Result rule 2: discriminator long

Spec: §7.5.1.1.5, p. 34 — “2. The Result union discriminator type shall be long.”

Repo: crates/rpc/src/codegen.rs::ExceptionCase::discriminator (i32); crates/lang-rules/src/emit/interface_cpp.rs::discriminator_field (Int32)

Tests: crates/rpc/src/codegen.rs::tests::the_exception_label_hashes_the_scoped_name

Status: done — commit 64d55a6c8f94.

§7.5.1.1.5 Result rule 3: case dds::RETCODE_OK

Spec: §7.5.1.1.5, p. 34 — “3. The Result union shall have a case with label dds::RETCODE_OK which is used to represent a successful return.”

Repo: crates/rpc/src/codegen.rs::RETCODE_OK; crates/lang-rules/src/emit/interface_cpp.rs::result_union_of

Tests: crates/rpc/src/codegen.rs::tests::the_result_union_of_seven_five_one_one_five_is_built (RETCODE_OK == 0)

Status: done — commit 64d55a6c8f94.

§7.5.1.1.5 Result rule 3a: member result of the Out type

Spec: §7.5.1.1.5, p. 34 — “a. This case label shall contain a single member with name “result” and type ${interfaceName}_${operationName}_Out.”

Repo: crates/rpc/src/codegen.rs::RESULT_MEMBER; crates/lang-rules/src/emit/interface_cpp.rs::result_union_of

Tests: crates/rpc/src/codegen.rs::tests::the_result_union_of_seven_five_one_one_five_is_built, crates/lang-rules/tests/interface_bindings.rs::cpp_declares_the_topic_types_of_seven_five

Status: done — commit 64d55a6c8f94.

§7.5.1.1.5 Result rule 4a: constant ${exceptionType}_Ex_Hash

Spec: §7.5.1.1.5, p. 34 — “a. A constant of type long and with name “${exceptionType}_Ex_Hash” shall be available in the same namespace as the interface is defined in.”

Repo: crates/lang-rules/src/emit/interface_cpp.rs::declare (constant with service.module); crates/lang-rules/src/adapter/interface.rs::exception_hash_constant

Tests: crates/lang-rules/tests/interface_bindings.rs::cpp_declares_the_topic_types_of_seven_five, crates/rpc/src/codegen.rs::tests::the_result_union_of_seven_five_one_one_five_is_built, crates/lang-rules/tests/interface_bindings.rs::the_topic_types_and_constants_stand_in_the_module_of_the_interface

Status: done — commits 64d55a6c8f94, 7036cde62638. Name, type (std::int32_t) and occurrence of the constant Overflow_Ex_Hash are tested. The test creates two modules, plus an exception in a third, and checks for C++ that the declaration stands in the namespace of its interface and neither in the global namespace nor in the namespace of the other module; the Rust binding places the items in the module of their interface. The placement of the Java classes is not checked; the Rust binding has no _Hash constants.

§7.5.1.1.5 Result rule 4b: HASH of the fully qualified name

Spec: §7.5.1.1.5, p. 34 — “b. The value of the constant shall be the HASH of the fully qualified name of the exception type where module separator to be used is “::” (2 colons).”

Repo: crates/rpc/src/service_mapping.rs::scoped_exception_name; crates/lang-rules/src/adapter/interface.rs::exception_hash

Tests: crates/rpc/src/codegen.rs::tests::the_exception_label_hashes_the_scoped_name (MD5 of robot::Overflow), crates/rpc/tests/language_binding_agreement.rs::both_readings_of_seven_five_produce_the_same_sample_structure (exception_hash in the generator equals the run-time value)

Status: done — commit 64d55a6c8f94. The name is built without a leading :: (robot::Overflow); the specification’s example on p. 34 hashes "TooFast" without the module.

§7.5.1.1.5 Result rule 5: one case per exception

Spec: §7.5.1.1.5, p. 34 — “5. The union shall have a case label for each exception declared as a possible outcome of the operation.”

Repo: crates/rpc/src/codegen.rs::build_result_union

Tests: crates/rpc/src/codegen.rs::tests::the_result_union_of_seven_five_one_one_five_is_built, crates/rpc/tests/language_binding_agreement.rs::both_readings_of_seven_five_produce_the_same_sample_structure (number of cases equals raises.len())

Status: done — commit 64d55a6c8f94.

§7.5.1.1.5 Result rule 5a: label ${exceptionType}_Ex_Hash

Spec: §7.5.1.1.5, p. 34 — “a. The integral value of the case label shall be ${exceptionType}_Ex_Hash.”

Repo: crates/rpc/src/codegen.rs::ExceptionCase (discriminator, hash_constant)

Tests: crates/rpc/src/codegen.rs::tests::the_exception_label_hashes_the_scoped_name

Status: done — commit 64d55a6c8f94.

§7.5.1.1.5 Result rule 5b: member _ex in lower case

Spec: §7.5.1.1.5, p. 34 — “b. The case label shall contain a single member with name synthetized as the lower-case of the exception name with the suffix “_ex” added.”

Repo: crates/rpc/src/codegen.rs::build_result_union (member); crates/lang-rules/src/adapter/interface.rs::exception_member_name

Tests: crates/rpc/src/codegen.rs::tests::the_result_union_of_seven_five_one_one_five_is_built (toofast_ex)

Status: done — commit 64d55a6c8f94.

§7.5.1.1.5 Result rule 5c: type of the exception

Spec: §7.5.1.1.5, p. 34 — “c. The type associated with the case member shall be the exception type.”

Repo: crates/lang-rules/src/emit/interface_cpp.rs::result_union_of

Tests: crates/lang-rules/tests/interface_bindings.rs::cpp_declares_the_topic_types_of_seven_five (Overflow overflow_ex;)

Status: done — commits 64d55a6c8f94, ad892a10764a.

§7.5.1.1.4 and §7.5.1.1.5 examples

Spec: §7.5.1.1.4–§7.5.1.1.5, pp. 32–35 — examples for RobotControl (“Non-normative Example”).

Repo: —

Tests: —

Status: n/a (informative) — examples.

§7.5.1.1.6 Call rule 1: ${interfaceName}_Call in the module of the interface

Spec: §7.5.1.1.6, p. 35 — “Each interface shall map to a Call union and a Request structure. […] 1. The Call union name shall be “${interfaceName}_Call” in the same module as the interface.”

Repo: crates/rpc/src/codegen.rs::build_call_union; crates/lang-rules/src/adapter/interface.rs::call_union_name; crates/lang-rules/src/emit/interface_cpp.rs::declare

Tests: crates/rpc/src/codegen.rs::tests::basic_request_has_header_and_call_union, crates/lang-rules/tests/interface_bindings.rs::cpp_declares_the_topic_types_of_seven_five, crates/lang-rules/tests/interface_bindings.rs::the_topic_types_and_constants_stand_in_the_module_of_the_interface

Status: done — commits b5224bd70dbb, ad892a10764a, 7036cde62638. The name Calculator_Call is tested. The test creates two modules, plus an exception in a third, and checks for C++ that the declaration stands in the namespace of its interface and neither in the global namespace nor in the namespace of the other module; the Rust binding places the items in the module of their interface. The placement of the Java classes is not checked; the Rust binding has no _Hash constants.

§7.5.1.1.6 Call rule 2: discriminator long

Spec: §7.5.1.1.6, p. 35 — “2. The Call union discriminator type shall be of type long.”

Repo: crates/rpc/src/codegen.rs::CallUnionCase::discriminator (i32); crates/lang-rules/src/emit/interface_cpp.rs::discriminator_field (Int32)

Tests: crates/rpc/src/codegen.rs::tests::the_case_label_is_the_published_hash_arithmetic

Status: done — commit 64d55a6c8f94.

§7.5.1.1.6 Call rule 3: default with unknownOp

Spec: §7.5.1.1.6, p. 35 — “3. The Call union shall have a default case label containing a member named “unknownOp” of type dds::rpc::UnknownOperation.”

Repo: crates/rpc/src/codegen.rs::UNKNOWN_OP_MEMBER; crates/lang-rules/src/emit/interface_cpp.rs::union_of

Tests: crates/rpc/src/codegen.rs::tests::both_unions_carry_the_default_unknown_operation_case, crates/lang-rules/tests/interface_bindings.rs::cpp_declares_the_topic_types_of_seven_five

Status: done — commit 64d55a6c8f94.

§7.5.1.1.6 Call rule 4: constant ${interfaceName}_${operationName}_Hash

Spec: §7.5.1.1.6, p. 35 — “4. For each operation in the interface, an integral constant of type long and name “$(interfaceName}_$ {operationName}_Hash” shall be present in the same module as the interface. The value of this constant is the HASH of unqualified ${operationName}.”

Repo: crates/rpc/src/codegen.rs::CallUnionCase::hash_constant; crates/lang-rules/src/emit/interface_cpp.rs::declare (hash_constant, operation_hash)

Tests: crates/rpc/src/codegen.rs::tests::the_case_labels_are_the_operation_hashes, crates/lang-rules/tests/interface_bindings.rs::cpp_declares_the_topic_types_of_seven_five, crates/lang-rules/tests/interface_bindings.rs::the_topic_types_and_constants_stand_in_the_module_of_the_interface

Status: done — commits 64d55a6c8f94, 7036cde62638. Name, type (std::int32_t) and value (HASH of the unqualified name) are tested. The test creates two modules, plus an exception in a third, and checks for C++ that the declaration stands in the namespace of its interface and neither in the global namespace nor in the namespace of the other module; the Rust binding places the items in the module of their interface. The placement of the Java classes is not checked; the Rust binding has no _Hash constants.

§7.5.1.1.6 Call rule 5: one case per operation

Spec: §7.5.1.1.6, p. 35 — “5. The Call union shall have a case label for each operation in the interface.”

Repo: crates/rpc/src/codegen.rs::build_call_union (over ServiceDef::all_methods, so the implied operations of the attributes are included)

Tests: crates/rpc/src/codegen.rs::tests::basic_request_has_header_and_call_union

Status: done — commits b5224bd70dbb, 259cf675efdf.

§7.5.1.1.6 Call rule 5a: label HASH of the operation name

Spec: §7.5.1.1.6, p. 35 — “a. The integral value of the case label shall be the HASH of ${operationName}.”

Repo: crates/rpc/src/codegen.rs::build_call_union (rpc_member_hash(&m.name))

Tests: crates/rpc/src/codegen.rs::tests::the_case_label_is_the_published_hash_arithmetic, crates/rpc/src/codegen.rs::tests::the_case_labels_are_the_operation_hashes

Status: done — commit 64d55a6c8f94. ### §7.5.1.1.6 Call rule 5b: member with the operation name

Spec: §7.5.1.1.6, p. 35 — “b. The member name for the case label shall be the operation name.”

Repo: crates/rpc/src/codegen.rs::CallUnionCase::method

Tests: crates/rpc/src/codegen.rs::tests::basic_request_has_header_and_call_union

Status: done — commit b5224bd70dbb.

§7.5.1.1.6 Call rule 5c: type ${interfaceName}_${operationName}_In

Spec: §7.5.1.1.6, p. 35 — “c. The type for the case label member shall be ${interfaceName}_${operationName}_In as defined in sub clause 7.5.1.1.2 The Hashing Algorithm.”

Repo: crates/rpc/src/codegen.rs::CallUnionCase::case_type_name

Tests: crates/rpc/src/codegen.rs::tests::basic_request_has_header_and_call_union

Status: done — commit b5224bd70dbb.

§7.5.1.1.4 to §7.5.1.1.6 Placement of the types and constants in the module — without test

Spec: §7.5.1.1.4 rule 2, §7.5.1.1.5 Out rule 2 and Result rule 4a, §7.5.1.1.6 rules 1 and 4 — as above.

Repo: crates/lang-rules/src/emit/interface_cpp.rs (namespace per module of the interface); crates/lang-rules/src/emit/interface_rust.rs (Rust module per module of the interface)

Tests: crates/lang-rules/tests/interface_bindings.rs::the_topic_types_and_constants_stand_in_the_module_of_the_interface

Status: done — the test has two modules a and b and an exception in a third module. For C++ it checks that Svc_f_In, Svc_f_Out, Svc_f_Result, Svc_Call, Svc_Return, Svc_Request, Svc_Reply, Svc_f_Hash and Bad_Ex_Hash stand in the namespace a only, and Other_g_In, Other_Call, Other_g_Hash in the namespace b only. For Rust it checks the placement of the structures and enumerations in the module of the interface; Rust generates no _Hash constants, so they are not checked there. Commit 7036cde62638. ### §7.5.1.1.6 Request rule 1: ${interfaceName}_Request in the module

Spec: §7.5.1.1.6, p. 36 — “1. The name of Request structure shall be “${interfaceName}_Request” in the same module as the interface.”

Repo: crates/rpc/src/codegen.rs::build_basic_pair (Commit 64d55a6c8f94); crates/lang-rules/src/adapter/interface.rs::request_type_name (Commit ad892a10764a)

Tests: crates/rpc/src/codegen.rs::tests::basic_pair_topic_names, crates/lang-rules/tests/interface_bindings.rs::cpp_declares_the_topic_types_of_seven_five

Status: done

§7.5.1.1.6 Request rule 2: two members

Spec: §7.5.1.1.6, p. 36 — “2. The Request structure shall have two members”.

Repo: crates/rpc/src/codegen.rs::build_basic_pair (Commit 64d55a6c8f94)

Tests: crates/rpc/src/codegen.rs::tests::basic_request_has_header_and_call_union

Status: done

§7.5.1.1.6 Request rule 2a: header of type RequestHeader

Spec: §7.5.1.1.6, p. 36 — “a. The first member of the Request structure shall be named “header” and be of type dds::rpc::RequestHeader.”

Repo: crates/rpc/src/codegen.rs::build_basic_pair (Commit 64d55a6c8f94)

Tests: crates/rpc/src/codegen.rs::tests::basic_request_has_header_and_call_union

Status: done

§7.5.1.1.6 Request rule 2b: data of type ${interfaceName}_Call

Spec: §7.5.1.1.6, p. 36 — “b. The second member of the Request structure shall be named “data” and be of type ${interfaceName}_Call.”

Repo: crates/rpc/src/codegen.rs::build_basic_pair (Commit 64d55a6c8f94)

Tests: crates/rpc/src/codegen.rs::tests::basic_request_has_header_and_call_union, crates/lang-rules/tests/interface_bindings.rs::cpp_declares_the_topic_types_of_seven_five

Status: done

§7.5.1.1.6 Examples

Spec: §7.5.1.1.6, pp. 36–37 — RobotControl_Call and RobotControl_Request (“Non-normative Example”).

Repo: —

Tests: —

Status: n/a (informative) — examples.

§7.5.1.1.7 Return rule 1: ${interfaceName}_Return in the module

Spec: §7.5.1.1.7, p. 37 — “Each interface shall map to a Return union and a Reply structure. […] 1. The Return union name shall be “${interfaceName}_Return” in the same module as the interface.”

Repo: crates/rpc/src/codegen.rs::build_call_union (with reply = true; Commit 64d55a6c8f94); crates/lang-rules/src/adapter/interface.rs::return_union_name (Commit 64d55a6c8f94)

Tests: crates/rpc/src/codegen.rs::tests::basic_reply_excludes_oneway_methods, crates/lang-rules/tests/interface_bindings.rs::cpp_declares_the_topic_types_of_seven_five

Status: done

§7.5.1.1.7 Return rule 2: discriminator long

Spec: §7.5.1.1.7, p. 37 — “2. The Return union discriminator type shall be of type long.”

Repo: crates/rpc/src/codegen.rs::CallUnionCase::discriminator (Commit 64d55a6c8f94)

Tests: crates/rpc/src/codegen.rs::tests::the_case_labels_are_the_operation_hashes

Status: done

§7.5.1.1.7 Return rule 3: default with unknownOp

Spec: §7.5.1.1.7, p. 37 — “3. The Return union shall have a default case label containing a member named “unknownOp” of type dds::rpc::UnknownOperation.”

Repo: crates/rpc/src/codegen.rs::build_call_union (default_member, UNKNOWN_OP_MEMBER; Commit 64d55a6c8f94)

Tests: crates/rpc/src/codegen.rs::tests::both_unions_carry_the_default_unknown_operation_case

Status: done

§7.5.1.1.7 Return rule 4a: constant ${interfaceName}_${operationName}_Hash

Spec: §7.5.1.1.7, p. 37 — “a. A constant of type long and with name “${interfaceName}_${operationName}_Hash” shall be available in the same namespace as the interface is defined in.”

Repo: crates/lang-rules/src/emit/interface_cpp.rs::declare (hash_constant, one constant per operation for both unions; Commit 64d55a6c8f94)

Tests: crates/lang-rules/tests/interface_bindings.rs::cpp_declares_the_topic_types_of_seven_five

Status: done

§7.5.1.1.7 Return rule 4b: HASH of the unqualified name

Spec: §7.5.1.1.7, p. 37 — “b. The value of the constant shall be the HASH of the name of the operation (not qualified).”

Repo: crates/lang-rules/src/adapter/interface.rs::operation_hash (Commit 64d55a6c8f94)

Tests: crates/rpc/src/codegen.rs::tests::the_case_labels_are_the_operation_hashes

Status: done

§7.5.1.1.7 Return rule 5: one case per operation

Spec: §7.5.1.1.7, p. 37 — “5. The Return union shall have a case label for each operation in the interface”.

Repo: crates/rpc/src/codegen.rs::build_call_union (Commit 64d55a6c8f94)

Tests: crates/rpc/src/codegen.rs::tests::basic_reply_excludes_oneway_methods

Status: done — oneway operations get no case (item for production (87) in §7.3.1.1).

§7.5.1.1.7 Return rule 5a: label ${interfaceName}_${operationName}_Hash

Spec: §7.5.1.1.7, p. 37 — “a. The integral value of the case label shall be ${interfaceName}_${operationName}_Hash as computed using the HASH algorithm of the unqualified name of the operation.”

Repo: crates/rpc/src/codegen.rs::build_call_union (Commit 64d55a6c8f94)

Tests: crates/rpc/src/codegen.rs::tests::the_case_labels_are_the_operation_hashes

Status: done

§7.5.1.1.7 Return rule 5b: member and type ${interfaceName}_${operationName}_Result

Spec: §7.5.1.1.7, p. 37 — “b. The member name for the case label shall be the operation name and the type shall be ${interfaceName}_${operationName}_Result.”

Repo: crates/rpc/src/codegen.rs::build_call_union (case_type_name; Commit 64d55a6c8f94)

Tests: crates/rpc/src/codegen.rs::tests::basic_reply_excludes_oneway_methods

Status: done

§7.5.1.1.7 Reply rule 1: ${interfaceName}_Reply

Spec: §7.5.1.1.7, p. 38 — “1. The Reply structure name shall be “${interfaceName}_Reply,”.”

Repo: crates/rpc/src/codegen.rs::build_basic_pair (Commit 64d55a6c8f94); crates/lang-rules/src/adapter/interface.rs::reply_type_name (Commit ad892a10764a)

Tests: crates/rpc/src/codegen.rs::tests::basic_pair_topic_names

Status: done

§7.5.1.1.7 Reply rule 2: in the module of the interface

Spec: §7.5.1.1.7, p. 38 — “2. The Reply structure shall be defined within the same module as the original interface.”

Repo: crates/lang-rules/src/emit/interface_cpp.rs::declare (Commit ad892a10764a)

Tests: crates/lang-rules/tests/interface_bindings.rs::cpp_declares_the_topic_types_of_seven_five

Status: done

§7.5.1.1.7 Reply rule 3: two members

Spec: §7.5.1.1.7, p. 38 — “3. The Reply structure shall have two members”.

Repo: crates/rpc/src/codegen.rs::build_basic_pair (Commit 64d55a6c8f94)

Tests: crates/rpc/src/codegen.rs::tests::basic_reply_excludes_oneway_methods

Status: done

§7.5.1.1.7 Reply rule 3a: header of type ReplyHeader

Spec: §7.5.1.1.7, p. 38 — “a. The first member of the Reply structure shall be named “header” and be of type dds::rpc::ReplyHeader.”

Repo: crates/rpc/src/codegen.rs::build_basic_pair (Commit 64d55a6c8f94)

Tests: crates/lang-rules/tests/interface_bindings.rs::cpp_declares_the_topic_types_of_seven_five

Status: done

§7.5.1.1.7 Reply rule 3b: data of type ${interfaceName}_Return

Spec: §7.5.1.1.7, p. 38 — “b. The second member of the Reply type shall be named “data” and be of type ${interfaceName}_Return.”

Repo: crates/rpc/src/codegen.rs::build_basic_pair (Commit 64d55a6c8f94)

Tests: crates/rpc/src/codegen.rs::tests::basic_reply_excludes_oneway_methods, crates/lang-rules/tests/interface_bindings.rs::cpp_declares_the_topic_types_of_seven_five

Status: done

§7.5.1.1.7 Examples

Spec: §7.5.1.1.7, pp. 37–38 — RobotControl_Return and RobotControl_Reply (“Non-normative Example”).

Repo: —

Tests: —

Status: n/a (informative) — examples. The example names the second member of RobotControl_Reply reply, rule 3b names it data.

§7.5.1.1.8 Inheritance does not change the types

Spec: §7.5.1.1.8, p. 38 — “Inheritance has no effect on the generated structures and unions. […] The Request and Reply types for a derived interface includes operations defined only in the derived interface.”

Repo: crates/lang-rules/src/emit/interface_cpp.rs::declare (topic types from service.all_operations(), the interface’s own operations only; Commit ad892a10764a); crates/lang-rules/src/emit/interface_rust.rs::declare (Commit 7751c4065bd3)

Tests: crates/rpc-rust-e2e/tests/e2e.rs::a_derived_client_reaches_an_inherited_operation_through_its_base_field (Commit 026f15d1df46)

Status: done

§7.5.1.1.8 N topics, N DataWriters and N DataReaders

Spec: §7.5.1.1.8, p. 38 — “A DDS service that implements a derived interface uses two topics for every interface in the hierarchy. As a result, a service implementing a hierarchy of N interfaces, shall have N request topics and N reply topics. Consequently, it will necessitate N DataWriters and N DataReaders. The types and the topic names are obtained as specified in 7.4.2 Basic Service Mapping.”

Repo: crates/lang-rules/src/emit/interface_rust.rs::client_impl (one Requester per level); crates/lang-rules/src/emit/interface_rust.rs (one dispatcher per level, each with its own Replier; Commit 7751c4065bd3)

Tests: crates/rpc-rust-e2e/tests/e2e.rs::a_derived_client_reaches_an_inherited_operation_through_its_base_field (Commit 026f15d1df46)

Status: done

§7.5.1.1.8 Calculator example

Spec: §7.5.1.1.8, pp. 38–43 — Basic mapping of Calculator : Adder, Subtractor (“Non-normative Example”).

Repo: —

Tests: —

Status: n/a (informative) — example. It differs from the rules: the Result unions have default: dds::rpc::UnknownException unknownEx and the label dds::rpc::REMOTE_EX_OK (rule 3 names dds::RETCODE_OK), Calculator_off_Result is written as struct ... switch (long), and Calculator_Reply has a header of type RequestHeader.

§7.5.1.2 Enhanced mapping

Spec: §7.5.1.2, p. 43 — “To accurately capture the semantics of the method call invocation and return, this specification defines additional built-in annotations. […] The Enhanced Service Mapping uses the [DDS-XTypes] type system in addition to the annotations defined in 7.5.1.2.1”.

Repo: crates/rpc/src/codegen.rs::build_enhanced_service and build_enhanced_service_with (Commit 0edbbcf11324); topic types and codecs in crates/lang-rules/src/emit/interface_rust/enhanced.rs (Commit 41b3b02f7a20), crates/lang-rules/src/emit/interface_cpp/enhanced.rs, crates/lang-rules/src/emit/interface_cpp/enhanced_codec.rs (Commit 45ead22cc2b9), crates/lang-rules/src/emit/interface_java/enhanced.rs, crates/lang-rules/src/emit/interface_java/enhanced_calls.rs (Commit 2ea77f7dad8a); selected by zerodds-idlc generate --rpc-mapping basic|enhanced|enhanced-empty (Commit c17fbe91ffe7); runtime zerodds_rpc::endpoint_options::RpcMapping::Enhanced (Commit e305669e2c42)

Tests: crates/rpc/src/codegen.rs::tests::enhanced_request_is_a_choice_over_the_operations, crates/lang-rules/tests/enhanced_bindings.rs::the_model_is_the_clause, crates/rpc-rust-e2e/tests/enhanced_e2e.rs::an_enhanced_call_is_answered_through_the_related_sample_identity

Status: done — the Request, Reply, In, Out and Result structures with @Choice, @Autoid, remoteEx and flat inheritance exist in the model and in the generators for Rust, C++ and Java; the Rust runtime correlates through PID_RELATED_SAMPLE_IDENTITY.

§7.5.1.2.1 Annotations in the module dds::rpc

Spec: §7.5.1.2.1, p. 43 — “All annotations below are defined in the dds::rpc module.”

Repo: crates/ast/src/node/annotation.rs (BUILTIN_ANNOTATIONS: Choice, Autoid, Empty, Mutable; Commit 6c7f585a36ee); crates/idl-lower/src/annotation.rs::Lowering::apply_user_annotation (Commit b53b12d04ba2)

Tests: crates/ast/tests/node_space.rs::every_builtin_annotation_of_the_spec_list_is_present, crates/idl-lower/tests/annotations.rs::the_dds_rpc_annotations_resolve_to_their_builtin_declarations, crates/idl-lower/tests/annotations.rs::the_qualified_dds_rpc_spelling_is_the_same_annotation

Status: done — the annotations of the module are predefined and resolve to the same declaration under their simple name (@Choice) and in the qualified spelling (@dds::rpc::Choice, @dds::rpc::Autoid) (test crates/idl-lower/tests/annotations.rs::the_qualified_dds_rpc_spelling_is_the_same_annotation, commit ecda940289b7). The model keeps the declarations in the built-in module @builtin; a module dds::rpc in crates/ast would move the fixed indices of the built-in nodes, and the spec asks for the name, not for a module structure of the model. A built-in annotation has no TypeObject and does not appear as ann_custom; the module name is visible in no output (no TypeObject and no generated file names the declaration; only scoped_name_of yields @builtin::Choice internally; read from the code, not measured) (9df3125c22b8, test crates/lang-rules/tests/enhanced_bindings.rs::a_choice_structure_written_in_idl_has_a_mutable_type_object_with_optional_members).

§7.5.1.2.1.1 @Choice: declaration

Spec: §7.5.1.2.1.1, p. 43 — “The @Choice annotation is a placeholder annotation defined as follows. @Annotation local interface Choice { };”

Repo: crates/ast/src/node/annotation.rs (BUILTIN_ANNOTATIONS, Eintrag Choice; Commit 6c7f585a36ee)

Tests: crates/ast/tests/node_space.rs::every_builtin_annotation_of_the_spec_list_is_present

Status: done — Choice is a predefined annotation without members.

§7.5.1.2.1.1 @Choice only on structures

Spec: §7.5.1.2.1.1, p. 43 — “The @Choice annotation is allowed on structures only.”

Repo: crates/idl-lower/src/annotation.rs::Lowering::misplaced (entry for Choice; Commit ecda940289b7)

Tests: crates/idl-lower/tests/annotations.rs::choice_is_refused_on_anything_but_a_structure

Status: done — @Choice on a union, a member, an interface and an enumeration is refused with an error; on a structure it is accepted.

§7.5.1.2.1.1 @Choice: MUTABLE and all members @Optional

Spec: §7.5.1.2.1.1, p. 43 — “When present, the structure shall be interpreted as if the structure had the @Extensibility(MUTABLE_EXTENSIBILITY) annotation and all the members of the structure had the @Optional annotation.”

Repo: crates/rpc/src/codegen.rs::autoid_choice; crates/lang-rules/src/emit/interface_rust/enhanced.rs (choice_codec: DHEADER and one EMHEADER per present member), crates/lang-rules/src/emit/interface_cpp/enhanced.rs (std::optional members), crates/lang-rules/src/emit/interface_cpp/enhanced_codec.rs, crates/lang-rules/src/emit/interface_java/enhanced.rs, crates/lang-rules/src/emit/interface_java/enhanced_calls.rs (Commits 41b3b02f7a20, 45ead22cc2b9, 2ea77f7dad8a)

Tests: crates/rpc-rust-e2e/tests/enhanced_generated.rs::a_request_is_a_mutable_structure_with_one_member, crates/lang-rules/tests/enhanced_cpp_calls.rs::the_codec_writes_the_member_ids_and_length_codes_of_the_clause, crates/lang-rules/tests/enhanced_java_calls.rs::the_codec_writes_the_member_ids_and_length_codes_of_the_clause, crates/idl-lower/tests/annotations.rs::a_choice_structure_is_mutable_with_every_member_optional, crates/idl-lower/tests/annotations.rs::a_choice_structure_cannot_be_final_or_appendable, crates/lang-rules/tests/enhanced_bindings.rs::a_choice_structure_written_in_idl_has_a_mutable_type_object_with_optional_members

Status: done — the structures the generator creates (Request, Reply, Result) are MUTABLE with optional members. For a @Choice structure written in IDL, crates/idl-lower sets MUTABLE and every member @optional; its TypeObject is MUTABLE with optional members. A @Choice structure explicitly declared @final or @appendable is an error. Commit ecda940289b7.

§7.5.1.2.1.1 @Choice: exactly one member present

Spec: §7.5.1.2.1.1, p. 43 — “Furthermore, exactly one member shall be present at any given time.”

Repo: crates/lang-rules/src/emit/interface_rust/enhanced.rs (enum with one variant per member); crates/lang-rules/src/emit/interface_cpp/enhanced_codec.rs and crates/lang-rules/src/emit/interface_java/enhanced_calls.rs (count of the members set when writing, error for a number other than 1; Commits 41b3b02f7a20, 45ead22cc2b9, 2ea77f7dad8a)

Tests: crates/rpc-rust-e2e/tests/enhanced_generated.rs::a_request_is_a_mutable_structure_with_one_member, crates/rpc-rust-e2e/tests/enhanced_generated.rs::a_request_with_two_active_members_is_refused, crates/rpc-rust-e2e/tests/enhanced_generated.rs::a_choice_without_a_member_is_refused, crates/lang-rules/tests/enhanced_java_calls.rs::a_choice_holds_exactly_one_member_on_both_sides_of_the_codec, crates/rpc/tests/java_enhanced_codec.rs::the_generated_java_service_and_client_answer_the_error_cases_of_the_clauses

Status: done — in Rust the enum form makes exactly one member present; the decoder refuses zero or two members (tests; commit f88947810821). In Java the encoder and the decoder refuse zero and more than one member, and the generated runtime answers with RemoteInvalidArgumentError (tests; commit 82ec363b6b82). In C++ the codec counts the members set when writing and throws dds::rpc::UnsupportedError for a number other than 1; the decoder refuses zero and two members (869a329a6b48). Test: crates/rpc/tests/cpp/enhanced_function_call_roundtrip.cpp through crates/rpc/tests/cpp_enhanced_function_call.rs::the_generated_enhanced_client_calls_the_generated_enhanced_service (octets with no member and with two members are refused and answered REMOTE_EX_INVALID_ARGUMENT on the wire; 49525d7e5e80, run on the Linux test host).

§7.5.1.2.1.2 @Autoid on structures and members

Spec: §7.5.1.2.1.2, p. 43 — “The @Autoid annotation shall be allowed on structures and data members.”

Repo: crates/ast/src/node/annotation.rs (BUILTIN_ANNOTATIONS, entry Autoid; Commit 6c7f585a36ee); crates/idl-lower/src/annotation.rs::enumerated_parameter (reads the argument HASH/SEQUENTIAL)

Tests: crates/ast/tests/node_space.rs::every_builtin_annotation_of_the_spec_list_is_present, crates/idl-lower/tests/annotations.rs::autoid_on_a_structure_assigns_hashed_member_ids, crates/idl-lower/tests/annotations.rs::autoid_on_a_member_hashes_that_members_name, crates/idl-lower/tests/annotations.rs::autoid_is_refused_where_there_are_no_member_ids, crates/lang-rules/tests/enhanced_bindings.rs::an_autoid_structure_written_in_idl_has_hashed_member_ids_in_its_type_object

Status: done — Lowering::misplaced allows @Autoid on structures and structure members and refuses it on other elements. On a structure written in IDL, Lowering::dds_rpc_autoid sets the member id of every member to the HASH of the member name (hashed_member_id); on a single member the HASH of its name applies. The TypeObject carries these ids. Commit ecda940289b7.

§7.5.1.2.1.2 Synthesized structures carry @Autoid

Spec: §7.5.1.2.1.2, p. 43 — “The structures of the topic types synthesized from the interface shall be annotated as @Autoid.”

Repo: crates/rpc/src/codegen.rs::autoid; crates/lang-rules/src/adapter/interface.rs::autoid_struct (Commit 0edbbcf11324)

Tests: crates/lang-rules/tests/enhanced_bindings.rs::the_model_is_the_clause

Status: done — every synthesized structure has autoid: true; the test compares the marks (@Autoid or @Choice @Autoid) of all structures of the Calculator example with the list from §7.5.1.2.

§7.5.1.2.1.2 Member ID is the HASH of the name

Spec: §7.5.1.2.1.2, p. 43 — “The @Autoid annotation indicates that the member-id of each member shall be computed using the HASH algorithm (defined in 7.5.1.1.2 The Hashing Algorithm) applied to the name of the member.”

Repo: crates/rpc/src/codegen.rs::autoid with MEMBER_ID_MASK and crate::rpc_hash::rpc_member_hash; crates/lang-rules/src/adapter/interface.rs::member_id (Commit 0edbbcf11324)

Tests: crates/rpc/src/codegen.rs::tests::enhanced_autoid_member_ids_are_the_hash_of_the_name, crates/lang-rules/tests/enhanced_bindings.rs::the_member_ids_are_the_hash_of_the_names, crates/rpc-rust-e2e/tests/enhanced_generated.rs::a_request_is_a_mutable_structure_with_one_member

Status: done — the member id is the HASH of the name (§7.5.1.1.2), masked to the low 28 bits (0x0FFF_FFFF) because an EMHEADER carries a member id of 28 bits in XTypes 1.3 §7.4.3.4.2. The HASH itself has 32 bits.

§7.5.1.2.1.2 Report collisions of member IDs as errors

Spec: §7.5.1.2.1.2, p. 44 — “The collisions of member-ids produced as a result of @Autoid annotation must be detected. If a structure annotated as @Autoid has a hash collision due to two or more member names map to the same hash-code, the collision shall be reported as an error.”

Repo: crates/rpc/src/codegen.rs::autoid (RpcError::MemberIdCollision; Commit 0edbbcf11324); crates/lang-rules/src/adapter/interface.rs::autoid_struct (BindingError::Codec; Commit 0edbbcf11324)

Tests: crates/rpc/src/codegen.rs::tests::enhanced_member_id_collision_is_an_error

Status: done — m9852 and m12254 give the same 28-bit id and yield MemberIdCollision. The generator path (autoid_struct in interface.rs) checks the same way; it has no test of its own.

§7.5.1.2.1.3 @Empty allows an empty structure

Spec: §7.5.1.2.1.3, p. 44 — “The @Empty annotation allows a structure to be empty. The code synthesized from an empty structure is implementation dependent.”

Repo: crates/rpc/src/codegen.rs::EmptyOperationStyle::EmptyAnnotation and EnhancedOptions (Commit d1824c24a497); zerodds-idlc generate --rpc-mapping enhanced-empty (Commit c17fbe91ffe7); codecs for a structure without members in crates/lang-rules/src/emit/interface_rust/enhanced.rs, crates/lang-rules/src/emit/interface_cpp/enhanced_codec.rs, crates/lang-rules/src/emit/interface_java/enhanced_calls.rs

Tests: crates/rpc/src/codegen.rs::tests::enhanced_empty_operation_can_be_an_empty_structure, crates/lang-rules/tests/enhanced_empty_style.rs::the_empty_structure_reading_gives_it_no_member, crates/rpc-rust-e2e/tests/enhanced_empty.rs::an_empty_structure_has_no_octets

Status: done — an operation with nothing to carry can be mapped as an empty structure with @Empty; the default stays the dummy member (§7.5.1.1.4 rule 3c, example in §7.5.1.2.6).

§7.5.1.2.1.4 @Mutable on operations

Spec: §7.5.1.2.1.4, p. 44 — “This annotation shall be allowed on interface operations.”

Repo: crates/lang-rules/src/adapter/interface.rs (Operation::mutable from applied_annotation(&op.facets, "Mutable")); crates/rpc/src/service_mapping.rs (MethodDef::mutable); Commits 6c7f585a36ee, b53b12d04ba2

Tests: crates/idl-lower/tests/annotations.rs::the_dds_rpc_annotations_resolve_to_their_builtin_declarations, crates/rpc/src/codegen.rs::tests::enhanced_mutable_operation_has_mutable_structures

Status: done — @Mutable on an operation resolves and is read.

§7.5.1.2.1.4 @Mutable makes call and return structures MUTABLE

Spec: §7.5.1.2.1.4, p. 44 — “The use of the @Mutable operation changes the type declaration of the synthesized call and return structures so that they are declared with the @Extensibility(MUTABLE_EXTENSIBILITY) annotation.”

Repo: crates/rpc/src/codegen.rs::build_enhanced_operation (method.mutable for In, Out and Result); crates/lang-rules/src/emit/interface_rust/enhanced.rs::mutable_struct_codec (Commit 41b3b02f7a20)

Tests: crates/rpc/src/codegen.rs::tests::enhanced_mutable_operation_has_mutable_structures, crates/rpc-rust-e2e/tests/enhanced_generated.rs::a_mutable_operation_has_mutable_structures, crates/lang-rules/tests/enhanced_cpp_calls.rs::the_codec_writes_the_member_ids_and_length_codes_of_the_clause

Status: done — the structures of the operation with @Mutable are MUTABLE, those of the other operations are not.

§7.5.1.2.2 In structure as in the Basic mapping

Spec: §7.5.1.2.2, p. 44 — “The mapping for interface operations is the same as defined in 7.5.1.1.2 The Hashing Algorithm with the following additional rules.”

Repo: crates/rpc/src/codegen.rs::build_enhanced_operation with method_in_members (Commit 0edbbcf11324)

Tests: crates/rpc/src/codegen.rs::tests::enhanced_inout_param_is_in_both_structures, crates/rpc/src/codegen.rs::tests::enhanced_empty_operation_has_a_dummy_member_by_default

Status: done — the In structure has the members of the Basic mapping (in and inout parameters, otherwise dummy).

§7.5.1.2.2 @Mutable: In structure MUTABLE

Spec: §7.5.1.2.2, p. 44 — “If the operation has the @Mutable annotation, then the synthesized In structure shall have the annotation @Extensibility(MUTABLE_EXTENSIBILITY).”

Repo: crates/rpc/src/codegen.rs::build_enhanced_operation (autoid_struct(..., method.mutable, ...); Commit 0edbbcf11324)

Tests: crates/rpc/src/codegen.rs::tests::enhanced_mutable_operation_has_mutable_structures, crates/rpc-rust-e2e/tests/enhanced_generated.rs::a_mutable_operation_has_mutable_structures

Status: done

§7.5.1.2.3 Out structure as in the Basic mapping, @Mutable

Spec: §7.5.1.2.3, p. 44 — “The rules for mapping the Out structure are identical to that defined in 7.5.1.1.5 […] 1. If the operation has the @Mutable annotation, then the synthesized Out structure shall have the annotation @Extensibility(MUTABLE_EXTENSIBILITY).”

Repo: crates/rpc/src/codegen.rs::build_enhanced_operation with method_out_members (Commit 0edbbcf11324)

Tests: crates/rpc/src/codegen.rs::tests::enhanced_out_carries_the_return_value, crates/rpc/src/codegen.rs::tests::enhanced_mutable_operation_has_mutable_structures

Status: done

§7.5.1.2.3 Result structure ${interfaceName}_${operationName}_Result

Spec: §7.5.1.2.3, p. 44 — “Each operation in the interface shall map to an Out structure and a Result structure. […] 2. The Result structure name shall be “${interfaceName}_${operationName}_Result.””

Repo: crates/rpc/src/codegen.rs::build_enhanced_operation (Commit 0edbbcf11324)

Tests: crates/rpc/src/codegen.rs::tests::enhanced_result_carries_out_and_the_exceptions

Status: done

§7.5.1.2.3 Result structure with @Choice

Spec: §7.5.1.2.3, p. 44 — “3. The Result structure shall have the annotation @Choice.”

Repo: crates/rpc/src/codegen.rs::build_enhanced_operation (autoid_choice; Commit 0edbbcf11324)

Tests: crates/rpc/src/codegen.rs::tests::enhanced_result_carries_out_and_the_exceptions, crates/lang-rules/tests/enhanced_bindings.rs::the_model_is_the_clause

Status: done

§7.5.1.2.3 Result structure with @Autoid

Spec: §7.5.1.2.3, p. 44 — “4. The Result structure shall have the annotation @Autoid.”

Repo: crates/rpc/src/codegen.rs::build_enhanced_operation (autoid_choice; Commit 0edbbcf11324)

Tests: crates/rpc/src/codegen.rs::tests::enhanced_result_carries_out_and_the_exceptions, crates/lang-rules/tests/enhanced_bindings.rs::the_model_is_the_clause

Status: done

§7.5.1.2.3 Result structure: first member result

Spec: §7.5.1.2.3, p. 44 — “5. The Result structure shall have a first member with name “result” and with type ${interfaceName}_${operationName}_Out.”

Repo: crates/rpc/src/codegen.rs::build_enhanced_operation (RESULT_MEMBER; Commit 0edbbcf11324)

Tests: crates/rpc/src/codegen.rs::tests::enhanced_result_carries_out_and_the_exceptions

Status: done ### §7.5.1.2.3 Result structure: one member per exception

Spec: §7.5.1.2.3, p. 44 — “6. The Result structure name shall have members for each exception an operation may raise. a. The member name shall be synthetized as the lower-case version of the exception name with the suffix “_ex” added. b. The type associated with the member shall be the exception type.”

Repo: crates/rpc/src/codegen.rs::build_enhanced_operation (member <exception>_ex, name in lower case), crates/lang-rules/src/adapter/interface.rs::enhanced_service

Tests: crates/rpc/src/codegen.rs::tests::enhanced_result_carries_out_and_the_exceptions, crates/lang-rules/tests/enhanced_bindings.rs::the_model_is_the_clause, crates/rpc-rust-e2e/tests/enhanced_generated.rs::a_result_is_a_choice_of_the_result_and_the_exceptions

Status: done — the model adds a member <lower-case name>_ex of the exception type for each exception (0edbbcf11324; 41b3b02f7a20 for the generators). The Rust binding encodes the member under the member id toobig_ex.

§7.5.1.2.3 @Mutable: Result structure MUTABLE

Spec: §7.5.1.2.3, p. 44 — “7. If the operation has the @Mutable annotation, then the synthesized Result structure shall have the annotation @Extensibility(MUTABLE_EXTENSIBILITY).”

Repo: crates/rpc/src/codegen.rs::build_enhanced_operation (MethodDef::mutable sets EnhancedStruct::mutable on In, Out and Result), crates/lang-rules/src/adapter/interface.rs::enhanced_service

Tests: crates/rpc/src/codegen.rs::tests::enhanced_mutable_operation_has_mutable_structures, crates/rpc-rust-e2e/tests/enhanced_generated.rs::a_mutable_operation_has_mutable_structures

Status: done — if the operation has @Mutable, In, Out and Result are MUTABLE, for other operations they are not (0edbbcf11324; 41b3b02f7a20). The second test checks the octets of the In structure (DHEADER and one EMHEADER per member); for Result only the model test checks it.

§7.5.1.2.4 Request structure ${interfaceName}_Request

Spec: §7.5.1.2.4, p. 45 — “Each interface shall map to a Request structure. […] 1. The Request structure name shall be “${interfaceName}_Request.””

Repo: crates/rpc/src/codegen.rs::build_enhanced_service_with (${interfaceName}_Request), crates/lang-rules/src/adapter/interface.rs::enhanced_service

Tests: crates/rpc/src/codegen.rs::tests::enhanced_request_is_a_choice_over_the_operations, crates/lang-rules/tests/enhanced_bindings.rs::the_model_is_the_clause

Status: done — each interface gets exactly one structure ${interfaceName}_Request (0edbbcf11324; 41b3b02f7a20). The generators for Rust, C++ and Java declare it (enhanced_bindings.rs::rust_declares_the_structures_of_the_clause, cpp_declares_the_structures_of_the_clause, java_declares_the_structures_of_the_clause).

§7.5.1.2.4 Request structure with @Choice

Spec: §7.5.1.2.4, p. 45 — “2. The Request structure shall have the @Choice annotation.”

Repo: crates/rpc/src/codegen.rs::autoid_choice, crates/lang-rules/src/adapter/interface.rs::enhanced_service

Tests: crates/rpc/src/codegen.rs::tests::enhanced_request_is_a_choice_over_the_operations, crates/lang-rules/tests/enhanced_bindings.rs::the_model_is_the_clause, crates/rpc-rust-e2e/tests/enhanced_generated.rs::a_request_is_a_mutable_structure_with_one_member

Status: done — EnhancedStruct::choice is set for the Request structure (0edbbcf11324; 41b3b02f7a20). The Rust binding encodes it as a PL_CDR2 object with exactly one member (DHEADER, EMHEADER, member).

§7.5.1.2.4 Request structure with @Autoid

Spec: §7.5.1.2.4, p. 45 — “3. The Request structure shall have the @Autoid annotation.”

Repo: crates/rpc/src/codegen.rs::autoid (member id = HASH of the name, 28 bits), crates/lang-rules/src/adapter/interface.rs::enhanced_service

Tests: crates/rpc/src/codegen.rs::tests::enhanced_autoid_member_ids_are_the_hash_of_the_name, crates/rpc/src/codegen.rs::tests::enhanced_member_id_collision_is_an_error, crates/lang-rules/tests/enhanced_bindings.rs::the_member_ids_are_the_hash_of_the_names

Status: done — the Request structure has @Autoid; the member id is the HASH of the member name cut to 28 bits (0edbbcf11324; 41b3b02f7a20). A collision of two names is an error (RpcError::MemberIdCollision).

§7.5.1.2.4 Request structure: one member per operation

Spec: §7.5.1.2.4, p. 45 — “4. The Request structure shall contain a member for each operation in the interface. a. The member name shall be the operation name. b. The member type shall be ${interfaceName}_${operationName}_In.”

Repo: crates/rpc/src/codegen.rs::build_enhanced_service_with (one member per operation, type ${I}_${op}_In), crates/lang-rules/src/adapter/interface.rs::enhanced_service

Tests: crates/rpc/src/codegen.rs::tests::enhanced_request_is_a_choice_over_the_operations, crates/rpc/src/codegen.rs::tests::enhanced_inheritance_is_flattened, crates/lang-rules/tests/enhanced_bindings.rs::the_model_is_the_clause

Status: done — the member name is the operation name, the type is ${interfaceName}_${operationName}_In; inherited operations carry the type name of their base interface (Adder_add_In). 0edbbcf11324; 41b3b02f7a20.

§7.5.1.2.5 Reply structure ${interfaceName}_Reply

Spec: §7.5.1.2.5, p. 46 — “Each interface shall map to a Reply structure. […] 1. The Reply structure name shall be “${interfaceName}_Reply”.”

Repo: crates/rpc/src/codegen.rs::build_enhanced_service_with (${interfaceName}_Reply), crates/lang-rules/src/adapter/interface.rs::enhanced_service

Tests: crates/rpc/src/codegen.rs::tests::enhanced_reply_has_the_results_and_remote_ex, crates/lang-rules/tests/enhanced_bindings.rs::the_model_is_the_clause

Status: done — each interface gets exactly one structure ${interfaceName}_Reply (0edbbcf11324; 41b3b02f7a20). The three generators declare it (enhanced_bindings.rs::rust_declares_the_structures_of_the_clause, cpp_declares_the_structures_of_the_clause, java_declares_the_structures_of_the_clause).

§7.5.1.2.5 Reply structure with @Choice

Spec: §7.5.1.2.5, p. 46 — “2. The Reply structure shall have the @Choice annotation.”

Repo: crates/rpc/src/codegen.rs::autoid_choice, crates/lang-rules/src/adapter/interface.rs::enhanced_service

Tests: crates/rpc/src/codegen.rs::tests::enhanced_reply_has_the_results_and_remote_ex, crates/lang-rules/tests/enhanced_bindings.rs::the_model_is_the_clause, crates/rpc-rust-e2e/tests/enhanced_generated.rs::a_reply_carries_remote_ex

Status: done — EnhancedStruct::choice is set for the Reply structure (0edbbcf11324; 41b3b02f7a20). The Rust binding encodes a Reply with remoteEx as an object with one member.

§7.5.1.2.5 Reply structure with @Autoid

Spec: §7.5.1.2.5, p. 46 — “3. The Reply structure shall have the @Autoid annotation.”

Repo: crates/rpc/src/codegen.rs::autoid, crates/lang-rules/src/adapter/interface.rs::enhanced_service

Tests: crates/rpc/src/codegen.rs::tests::enhanced_autoid_member_ids_are_the_hash_of_the_name, crates/lang-rules/tests/enhanced_bindings.rs::the_member_ids_are_the_hash_of_the_names

Status: done — the Reply structure has @Autoid, member id as for the Request structure (0edbbcf11324; 41b3b02f7a20). the_member_ids_are_the_hash_of_the_names checks all structures of the model, the Reply structure included.

§7.5.1.2.5 Reply structure: one member per operation

Spec: §7.5.1.2.5, p. 46 — “4. The Reply structure shall contain a member for each operation in the interface. a. The member name shall be the operation name. b. The member type shall be ${interfaceName}_${operationName}_Result.”

Repo: crates/rpc/src/codegen.rs::build_enhanced_service_with (one member per operation, type ${I}_${op}_Result), crates/lang-rules/src/adapter/interface.rs::enhanced_service

Tests: crates/rpc/src/codegen.rs::tests::enhanced_reply_has_the_results_and_remote_ex, crates/rpc/src/codegen.rs::tests::enhanced_inheritance_is_flattened, crates/lang-rules/tests/enhanced_bindings.rs::the_model_is_the_clause

Status: done — the member name is the operation name, the type is ${interfaceName}_${operationName}_Result; inherited operations carry the type name of the base (Subtractor_sub_Result). 0edbbcf11324; 41b3b02f7a20.

§7.5.1.2.5 Reply structure: member remoteEx

Spec: §7.5.1.2.5, p. 46 — “5. The Reply structure shall contain a member named “remoteEx” of type dds::rpc::RemoteException_t. If an interface has an operation named remoteEx (case-sensitive), the corresponding Reply structure shall contain a member named remoteEx_N and type RemoteException_t, where N is the first integer in the range 1 to 2^31 that avoids the collision.”

Repo: crates/rpc/src/codegen.rs::remote_ex_member_name, crates/lang-rules/src/adapter/interface.rs::remote_ex_member_name, crates/rpc/src/enhanced.rs::encode_remote_ex_reply

Tests: crates/rpc/src/codegen.rs::tests::enhanced_reply_has_the_results_and_remote_ex, crates/rpc/src/codegen.rs::tests::enhanced_remote_ex_avoids_an_operation_of_that_name, crates/rpc/src/enhanced.rs::tests::a_remote_ex_member_renamed_for_a_colliding_operation_is_found_by_its_name, crates/rpc-rust-e2e/tests/enhanced_e2e.rs::an_enhanced_remote_exception_is_the_remote_ex_member

Status: done — the Reply structure has the member remoteEx; if an operation has that name, it is remoteEx_N with the first free N from 1 (0edbbcf11324; 41b3b02f7a20). The type is RemoteExceptionCode_t: the spec does not define the type dds::rpc::RemoteException_t it names, §7.5.1.1.1 and §7.5.2 define RemoteExceptionCode_t (contradiction inside the spec). The tests check N = 1; a case with an operation named remoteEx_1 (N = 2) has no test.

§7.5.1.2.2 to §7.5.1.2.5 examples

Spec: §7.5.1.2.3–§7.5.1.2.5, pp. 45–46 — examples for RobotControl (“Non-normative example”).

Repo: —

Tests: —

Status: n/a (informative) — examples. The structures of the example are covered by the items for §7.5.1.2.3 to §7.5.1.2.5.

§7.5.1.2.6 Inheritance is flattened

Spec: §7.5.1.2.6, p. 46 — “A derived interface is interpreted as if all the inherited operations are declared in-place in the derived interface. That is, the inheritance structure is flattened.”

Repo: crates/rpc/src/codegen.rs::build_enhanced_service_with (inherited operations first, base by base, then the interface’s own), crates/lang-rules/src/adapter/interface.rs::enhanced_service (through operations_with_interface_flattened), crates/lang-rules/src/emit/interface_rust/enhanced.rs (derived dispatcher)

Tests: crates/rpc/src/codegen.rs::tests::enhanced_inheritance_is_flattened, crates/lang-rules/tests/enhanced_bindings.rs::the_model_is_the_clause, crates/rpc-rust-e2e/tests/enhanced_generated.rs::a_derived_request_has_the_inherited_operation, crates/rpc-rust-e2e/tests/enhanced_generated.rs::a_derived_dispatcher_serves_an_inherited_member

Status: done — Request and Reply of the derived interface contain the inherited operations under the type names of the base; the derived dispatcher answers them (0edbbcf11324, 41b3b02f7a20, 7607e8680852).

§7.5.1.2.6 Calculator example

Spec: §7.5.1.2.6, pp. 46–49 — Enhanced mapping of Calculator : Adder, Subtractor (“Non-normative Example”).

Repo: —

Tests: crates/lang-rules/tests/enhanced_bindings.rs::the_model_is_the_clause (takes the example as its fixture)

Status: n/a (informative) — example. The structures of the example are the expectation in the_model_is_the_clause.

§7.5.1.2.6 Compatibility through the assignability rules

Spec: §7.5.1.2.6, p. 49 — “The Enhanced Service Mapping leverages the assignability rules defined in the [DDS-XTypes] specification to ensure that the topic types remain compatible in case of inheritance. A client using the base interface can invoke an operation in a service that implements a derived interface as long as the same topic names are used.”

Repo: crates/rpc/src/codegen.rs::build_enhanced_service_with (same member ids and type names of the base, topic_aliases per parent through ServiceDef::topic_names), crates/discovery/src/sedp/cache.rs::topics_correspond (matching through topic_aliases)

Tests: crates/rpc/src/codegen.rs::tests::enhanced_inheritance_is_flattened, crates/rpc/src/topic_naming.rs::tests::every_parent_interface_contributes_one_alias, crates/dcps/tests/topic_alias_matching.rs::a_reader_on_an_alias_matches_the_writer_over_the_wire, crates/rpc-rust-e2e/tests/enhanced_generated.rs::a_member_the_interface_does_not_have_is_unknown_operation, crates/rpc-rust-e2e/tests/java_peer.rs::a_java_client_calls_a_rust_service, crates/rpc-rust-e2e/tests/java_peer.rs::a_rust_client_calls_a_java_service, crates/rpc-rust-e2e/tests/java_peer.rs::a_java_client_of_the_base_calls_a_rust_service_of_the_derived_interface, crates/rpc-rust-e2e/tests/java_peer.rs::a_rust_client_of_the_base_calls_a_java_service_of_the_derived_interface, crates/java-omgdds/java/src/test/java/org/zerodds/rtps/TypeConsistencyTest.java

Status: done — Rust and C++ are implemented and measured: the same member ids for inherited operations, topic aliases of the parents, matching by alias (bdf9ab1e6caa), skipping of unknown members, and the topics carry the TypeInformation of their types, so that decide_type_consistency evaluates assignability (Rust a2bc3b857739; C++ through zerodds_writer_create_qos_typed and zerodds_reader_create_qos_typed of the C API, 1f0f710986f4, bb1220c3d1b2). Tests: crates/rpc-rust-e2e/tests/enhanced_type_information.rs::base_and_derived::a_base_client_calls_a_derived_service (Rust), crates/rpc/tests/cpp_rpc_real_library.rs::the_cpp_binding_runs_against_libzerodds (C++, old client against new service through ev_old/ev_new), structure of the objects: crates/lang-rules/tests/enhanced_type_information.rs (Linux test host, green). The Java runtime announces the TypeInformation (TypeDescription, RawTypeSupport, written by the generator: 145d0036dd82, 87d07b3ff2a3); the generated Java code is compiled and has run (crates/rpc/tests/java_rpc_runtime.rs), and a Java peer against a Rust peer is measured (dbb935492284, tests java_peer.rs, Linux test host). Java matches by assignability as Rust does (2d0f809c6e2, 9b1608508c5, d67a980f80b; item “§7.5.1.2.6 Java: matching of endpoints by aliases and assignability”): crates/rpc-rust-e2e/tests/java_peer.rs measures against Rust peers the client of the base against the service of the derived interface in both directions, a changed parameter type and a return type widened to long long (both without a match on the Java side) and a member appended to a @mutable structure (match, the reply is read); unit test TypeConsistencyTest.java (9 cases).

§7.5.2 Local and remote error codes

Spec: §7.5.2, pp. 49–50 — “Error codes are (conceptually) classified as local and remote. The error codes described in the [DDS] PIM are all local error codes. This specification further adds remote error codes […] represented using the RemoteExceptionCode_t IDL enumeration below.”

Repo: —

Tests: —

Status: n/a (informative) — classification; the enumeration is listed with §7.5.1.1.1.

§7.5.2 REMOTE_EX_OK

Spec: §7.5.2, p. 50 — “REMOTE_EX_OK — The request was executed successfully.”

Repo: crates/rpc/src/replier.rs::Replier::tick (RemoteExceptionCode::Ok after a successful handler), Replier::send_reply

Tests: crates/rpc/src/replier.rs::tests::tick_processes_request_and_writes_reply, crates/rpc/src/replier.rs::tests::receive_requests_and_send_reply_expose_the_identity

Status: done — the replier writes the code Ok with the reply; commit of the tests f06c1eaf3d3a (replier), c5af5c7c138e (send_reply).

§7.5.2 REMOTE_EX_UNSUPPORTED

Spec: §7.5.2, p. 50 — “REMOTE_EX_UNSUPPORTED — Operation is valid but it is unsupported (a.k.a. not implemented).”

Repo: crates/lang-rules/src/emit/interface_rust.rs::dispatcher_handle_fn (unknown operation, §7.7.1.1), crates/lang-rules/src/emit/interface_java/calls.rs (dispatcher of the Java service), crates/rpc/src/replier.rs::Replier::send_exception

Tests: crates/rpc-rust-e2e/tests/e2e.rs::the_generated_calculator_binding_runs_every_call, crates/rpc/tests/java_rpc_runtime.rs::the_generated_function_call_client_calls_the_generated_service (FunctionCallRoundtrip.java), crates/rpc/tests/cpp_function_call.rs::the_generated_client_calls_the_generated_service (function_call_roundtrip.cpp), crates/rpc/src/replier.rs::tests::send_exception_answers_with_the_code

Status: done — the generated Rust dispatcher, the generated Java service and the generated C++ service answer an operation the service does not know with REMOTE_EX_UNSUPPORTED in the Basic mapping (§7.7.1.1; Rust b527a9f58028, Java c512ee365514, C++ 62ccb5f757a3). The default branch of answer_method in crates/lang-rules/src/emit/interface_cpp/calls.rs throws RemoteUnsupportedError; function_call_roundtrip.cpp expects that error at the client.

§7.5.2 REMOTE_EX_INVALID_ARGUMENT

Spec: §7.5.2, p. 50 — “REMOTE_EX_INVALID_ARGUMENT — The value of the parameter passed has an illegal value (e.g., two options active in a @Choice structure).”

Repo: crates/rpc/src/replier.rs::Replier::tick (payload not decodable, and code of the handler), runtime/cpp/include/dds/rpc/core.hpp::detail::remote_exception_code_of (RemoteInvalidArgumentError)

Tests: crates/rpc/src/replier.rs::tests::tick_propagates_handler_error_into_reply, crates/rpc/src/replier.rs::tests::tick_answers_an_undecodable_payload_with_invalid_argument, crates/rpc/src/replier.rs::tests::receive_requests_answers_an_undecodable_payload_with_invalid_argument, crates/rpc/tests/runtime_e2e.rs::e2e_handler_error_surfaces_as_remote_exception_at_caller, crates/rpc-rust-e2e/tests/enhanced_generated.rs::a_request_with_two_active_members_is_refused, crates/rpc-rust-e2e/tests/enhanced_generated.rs::a_choice_without_a_member_is_refused, crates/rpc-rust-e2e/tests/enhanced_generated.rs::the_generated_service_answers_two_active_members_with_invalid_argument, crates/rpc/tests/java_enhanced_codec.rs::the_generated_java_service_and_client_answer_the_error_cases_of_the_clauses (EnhancedRuntimeChecks.java), crates/lang-rules/tests/enhanced_java_calls.rs::a_choice_holds_exactly_one_member_on_both_sides_of_the_codec, crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together (rpc_runtime_roundtrip.cpp)

Status: done — the code is sent when the handler supplies it, when the payload of a request cannot be decoded and when a @Choice structure holds two active options or none. Rust: Replier::tick and Replier::receive_requests (commits f88947810821, 58b9ca260b4c). Java: the generated decoder refuses, the runtime answers (82ec363b6b82). C++: Replier::pull in runtime/cpp/include/dds/rpc.hpp answers a request it cannot decode with REMOTE_EX_INVALID_ARGUMENT, in the Enhanced mapping through the identity of the sample, in the Basic mapping through the identity in the header (before, it was dropped; 49525d7e5e80). Test: crates/rpc/tests/cpp_enhanced_function_call.rs::the_generated_enhanced_client_calls_the_generated_enhanced_service (the answer on the wire, run on the Linux test host). The path through the handler is tested in C++ (RemoteInvalidArgumentError). Commits of the earlier parts: f06c1eaf3d3a (path through the handler), e305669e2c42 (error reply with the default case of the Return union).

§7.5.2 REMOTE_EX_OUT_OF_RESOURCES

Spec: §7.5.2, p. 50 — “REMOTE_EX_OUT_OF_RESOURCES — The remote service ran out of resources while processing the request.”

Repo: crates/rpc/src/replier.rs::Replier::send_exception, runtime/cpp/include/dds/rpc/core.hpp::detail::remote_exception_code_of (RemoteOutOfResourcesError)

Tests: crates/rpc/src/replier.rs::tests::tick_answers_out_of_resources, crates/rpc/tests/runtime_e2e.rs::e2e_out_of_resources_surfaces_as_remote_exception_at_caller, crates/rpc/src/replier.rs::tests::send_exception_answers_with_the_code, crates/rpc/tests/java_rpc_runtime.rs::the_java_rpc_runtime_and_the_generated_services_run_together (RpcRuntimeRoundtrip.java, RemoteOutOfResourcesError)

Status: done — an application sends the code through the handler (Err(RemoteExceptionCode::OutOfResources)), in C++ and Java through RemoteOutOfResourcesError. Rust: the replier writes the code, the caller receives RemoteException(OutOfResources) (58b9ca260b4c). Java: the test throws the error in the service and checks it at the client. In C++ rpc_runtime_roundtrip.cpp checks only the class relation of the error class (static_assert). No runtime detects a lack of resources itself; the spec does not define when a service reports a lack of resources. The Rust runtime does not send the code for a failure to encode the reply; that case reports REMOTE_EX_UNKNOWN_EXCEPTION (b527a9f58028).

§7.5.2 REMOTE_EX_UNKNOWN_OPERATION

Spec: §7.5.2, p. 50 — “REMOTE_EX_UNKNOWN_OPERATION — The operation called is unknown.”

Repo: crates/lang-rules/src/emit/interface_rust/enhanced.rs::answer_unknown_operations (Enhanced, §7.7.2), crates/lang-rules/src/emit/interface_java/enhanced_calls.rs, crates/lang-rules/src/emit/interface_cpp/calls.rs::answer_member

Tests: crates/rpc-rust-e2e/tests/enhanced_generated.rs::an_unknown_member_is_answered_unknown_operation, crates/rpc-rust-e2e/tests/enhanced_generated.rs::a_member_the_interface_does_not_have_is_unknown_operation, crates/rpc-rust-e2e/tests/enhanced_e2e.rs::an_enhanced_remote_exception_is_the_remote_ex_member, crates/rpc/tests/cpp_enhanced_function_call.rs::the_generated_enhanced_client_calls_the_generated_enhanced_service (enhanced_function_call_roundtrip.cpp), crates/rpc/tests/java_enhanced_codec.rs::the_generated_java_service_and_client_answer_the_error_cases_of_the_clauses (EnhancedRuntimeChecks.java)

Status: done — in the Enhanced mapping the generated dispatchers answer an unknown operation with REMOTE_EX_UNKNOWN_OPERATION (§7.7.2.1; Rust 41b3b02f7a20). The behaviour is tested with a running peer for Rust, C++ (enhanced_function_call_roundtrip.cpp) and Java (EnhancedRuntimeChecks.java, 82ec363b6b82). The Basic mapping sends REMOTE_EX_UNSUPPORTED in this case (§7.7.1.1, item above).

§7.5.2 REMOTE_EX_UNKNOWN_EXCEPTION

Spec: §7.5.2, p. 50 — “REMOTE_EX_UNKNOWN_EXCEPTION — A generic, unspecified exception was raised by the service implementation.”

Repo: crates/lang-rules/src/emit/interface_rust.rs::dispatcher_call_arm_via (wildcard arm), crates/rpc/src/replier.rs::Replier::tick (failure to encode the reply), runtime/cpp/include/dds/rpc/core.hpp::detail::remote_exception_code_of, crates/lang-rules/src/emit/interface_java/calls.rs

Tests: crates/rpc/tests/cpp_function_call.rs::the_generated_client_calls_the_generated_service (function_call_roundtrip.cpp), crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together (rpc_runtime_roundtrip.cpp), crates/rpc/tests/java_rpc_runtime.rs::the_generated_function_call_client_calls_the_generated_service (FunctionCallRoundtrip.java), crates/rpc-rust-e2e/tests/e2e.rs::an_exception_the_operation_does_not_declare_is_unknown_exception, crates/rpc-rust-e2e/tests/enhanced_generated.rs::an_exception_the_operation_does_not_declare_is_unknown_exception, crates/rpc-rust-e2e/tests/enhanced_generated.rs::the_generated_client_reports_unknown_exception_for_an_unknown_result_member

Status: done — an exception of the implementation that the operation does not declare and that is not a remote code is sent as REMOTE_EX_UNKNOWN_EXCEPTION in C++ and Java and raised at the client as RemoteUnknownExceptionError (C++ ec3707125a9b, Java c512ee365514). The generated Rust dispatcher sends the code for an undeclared exception (tests above, f88947810821); the Rust client reports an unknown member of the result as UnknownException. There is no test for Replier::tick with a reply that cannot be encoded (b527a9f58028).

§7.5.2 — use of the codes

Spec: §7.5.2, p. 50 — table of meanings.

Repo: crates/rpc/src/replier.rs::Replier::send_error_reply, crates/rpc/src/wire_codec.rs::ERROR_REPLY_DATA

Tests: crates/rpc/src/replier.rs::tests::tick_propagates_handler_error_into_reply, crates/rpc/src/replier.rs::tests::send_exception_answers_with_the_code

Status: done — the assignment of the codes to the cases is in the items for the individual codes; all six match the spec in Rust, C++ and Java (REMOTE_EX_INVALID_ARGUMENT in C++: 49525d7e5e80). A reply with an error code holds the header and the default case of the Return union (§7.5.1.1.7 rule 3); both tests check payload == ERROR_REPLY_DATA (e305669e2c42).

§7.5.2 Mapping to exceptions in C++ and Java

Spec: §7.5.2, p. 50 — “Both local and remote exception codes map to exceptions in the C++ and Java language bindings defined in 7.11 Language Bindings.”

Repo: —

Tests: —

Status: n/a (informative) — reference; the mapping is in §7.11.1.3 and §7.11.2.1.


§7.6 Discovering and Matching RPC Services

§7.6.1 Basic: built-in discovery without extension

Spec: §7.6.1, p. 50 — “The Basic Service Mapping relies on the built-in discovery provided by the underlying [DDS] compliant implementation. It does not use any extensions to the DDS discovery built-in topics.”

Repo: crates/rpc/src/requester.rs::Requester::from_topics, crates/rpc/src/replier.rs::Replier::from_topics (ordinary DataWriter and DataReader of the DCPS layer; set_rpc_discovery is called only for RpcMapping::Enhanced)

Tests: crates/rpc-rust-e2e/tests/e2e.rs::the_generated_calculator_binding_runs_every_call, crates/rpc/src/requester.rs::tests::the_basic_mapping_sends_without_a_service_match

Status: done — the Basic mapping uses the built-in discovery of DCPS; no parameter of the extension is announced (e305669e2c42).

§7.6.1 Endpoints of client and service through the built-in topics

Spec: §7.6.1, p. 50 — “A client comprises one (or more) DataWriter to send requests and one (or more) DataReader to receive replies. Similarly, a service implementation comprises one (or more) DataReader to receive requests and one (or more) DataWriter to send replies. The built-in publication and subscription topics are used to discover the DataWriter and DataReader at both sides.”

Repo: crates/rpc/src/requester.rs::Requester::from_topics, crates/rpc/src/replier.rs::Replier::from_topics

Tests: crates/rpc-rust-e2e/tests/e2e.rs::the_generated_calculator_binding_runs_every_call

Status: done — the requester creates a DataWriter for requests and a DataReader for replies, the replier a DataReader and a DataWriter; the pairing runs through the built-in publication and subscription topics (f06c1eaf3d3a).

§7.6.1 Note on the race condition

Spec: §7.6.1, p. 50 — “Non-normative Note: Service discovery for the Basic Service Mapping is not robust because discovery race conditions can cause the service replies to be lost.”

Repo: —

Tests: crates/rpc/src/requester.rs::tests::the_basic_mapping_sends_without_a_service_match

Status: n/a (informative) — note. Under the Basic mapping the Rust Requester writes a request at once, without waiting for the reply reader to match (Requester::service_matched is always true there).

§7.6.2 Enhanced: extension of the built-in topics

Spec: §7.6.2, p. 51 — “The Enhanced Service Mapping relies on the built-in discovery service provided by DDS. However, it extends the built-in publication and subscription topic data to avoid the discovery race conditions.” Plus the Design Rationale.

Repo: —

Tests: —

Status: n/a (informative) — introduction; the extension and the rules are in the items below.

§7.6.2 Client: request only after discovery of the service DataWriter

Spec: §7.6.2, p. 51 — “A client must ensure that the client-side DataReader has discovered the service-side DataWriter before writing a request to the service-side DataReader.”

Repo: crates/rpc/src/requester.rs::Requester::wait_for_service, Requester::service_matched, crates/rpc/src/discovery_ext.rs::service_matching_complete (Figure 7.4), runtime/cpp/include/dds/rpc/base.hpp::service_matching_complete, runtime/java/src/main/java/org/zerodds/ddsrpc/RequesterImpl.java

Tests: crates/rpc/src/requester.rs::tests::an_enhanced_request_waits_for_the_service_and_fails_without_sending, crates/rpc/src/requester.rs::tests::the_fail_setting_does_not_wait, crates/rpc/src/discovery_ext.rs::tests::the_client_waits_for_both_service_endpoints, crates/rpc-rust-e2e/tests/enhanced_e2e.rs::the_client_waits_for_the_service_instance_it_names, crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together, crates/zerodds-c-api/tests/rpc_discovery.rs::the_extension_is_announced_read_and_decides_the_matching, crates/rpc/tests/java_rpc_runtime.rs::the_java_rpc_runtime_and_the_generated_services_run_together

Status: done — Rust (e305669e2c42) and C++ (4b6b049312ff, 17a3aef74360) send an Enhanced request only when the request writer and the reply reader have found a service together (Figure 7.4: the endpoints name each other through the related key, and the request reader of the service announces the instance name the client names); ServiceMatching::Queue is the default, Fail and Off are named alternatives. crates/java-omgdds writes and reads PIDs 0x0080 to 0x0082 (rtps/RpcDiscovery.java, DiscoveryData.buildEndpoint and parseEndpoint, bound string<256>: an announcement beyond it is refused as in the decoder of crates/rtps; f65fb3965b5e). ZeroDdsParticipant announces service_instance_name on the endpoints of the service and related_*_key on both sides (9993349aff89). Tests: crates/java-omgdds/java/src/test/java/org/zerodds/rtps/RpcDiscoveryTest.java (theThreeParametersTravelWithTheEndpoint, aStringBeyondTheBoundIsRefused, aTopicCorrespondsByNameOrByAlias). The Java runtime applies the matching rule from the announced endpoints (1fddccd2b87b): ReplierImpl holds back the requests of a client whose reply reader the reply writer does not know (Figure 7.3, per client); RequesterImpl sends when the instance’s request reader names a reply writer that the reply reader has discovered (Figure 7.4). An endpoint without an announcement and a binding without discovery data keep the match by topic. Test: crates/rpc/tests/java/RpcRuntimeRoundtrip.java::overTheJavaPsm through crates/rpc/tests/java_rpc_runtime.rs::the_java_rpc_runtime_and_the_generated_services_run_together (needs a JDK; not run on the Mac or on the Linux test host).

§7.6.2 Service: request only after discovery of the client DataReader

Spec: §7.6.2, p. 51 — “A service must ensure that service-side DataWriter has discovered the client-side DataReader before a request is accepted by the service-side DataReader.”

Repo: crates/rpc/src/replier.rs::Replier::take_requests (holds back requests of a client that is not discovered completely), crates/rpc/src/discovery_ext.rs::client_matching_complete (Figure 7.3), runtime/cpp/include/dds/rpc/base.hpp::client_matching_complete, runtime/java/src/main/java/org/zerodds/ddsrpc/ReplierImpl.java

Tests: crates/rpc/src/replier.rs::tests::an_enhanced_request_of_an_undiscovered_client_is_held, crates/rpc/src/replier.rs::tests::the_named_alternatives_release_a_request_of_an_undiscovered_client, crates/rpc/src/discovery_ext.rs::tests::the_service_unmasks_a_client_once_both_its_endpoints_are_discovered, crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together, crates/zerodds-c-api/tests/rpc_discovery.rs::the_extension_is_announced_read_and_decides_the_matching

Status: done — Rust (e305669e2c42) and C++ (17a3aef74360) hold an Enhanced request back until the reply reader of the sending client is discovered (Figure 7.3); ClientMatching::Hold is the default, Off and accept_unannounced are named alternatives. The Rust runtime holds at most HELD_REQUESTS_MAX requests, further ones are counted by Replier::held_overflow. crates/java-omgdds writes and reads PIDs 0x0080 to 0x0082 (rtps/RpcDiscovery.java, DiscoveryData.buildEndpoint and parseEndpoint, bound string<256>: an announcement beyond it is refused as in the decoder of crates/rtps; f65fb3965b5e). ZeroDdsParticipant announces service_instance_name on the endpoints of the service and related_*_key on both sides (9993349aff89). Tests: crates/java-omgdds/java/src/test/java/org/zerodds/rtps/RpcDiscoveryTest.java (theThreeParametersTravelWithTheEndpoint, aStringBeyondTheBoundIsRefused, aTopicCorrespondsByNameOrByAlias). The Java runtime applies the matching rule from the announced endpoints (1fddccd2b87b): ReplierImpl holds back the requests of a client whose reply reader the reply writer does not know (Figure 7.3, per client); RequesterImpl sends when the instance’s request reader names a reply writer that the reply reader has discovered (Figure 7.4). An endpoint without an announcement and a binding without discovery data keep the match by topic. Test: crates/rpc/tests/java/RpcRuntimeRoundtrip.java::overTheJavaPsm through crates/rpc/tests/java_rpc_runtime.rs::the_java_rpc_runtime_and_the_generated_services_run_together (needs a JDK; not run on the Mac or on the Linux test host).

§7.6.2.1 Extended types of the built-in topics

Spec: §7.6.2.1, p. 51 — “This specification extends both PublicationBuiltinTopicData and SubscriptionBuiltinTopicData.” Plus the Design Rationale on the ParameterList.

Repo: —

Tests: —

Status: n/a (informative) — introduction; the members are in §7.6.2.1.1 and §7.6.2.1.2.

§7.6.2.1.1 service_instance_name with PID 0x0080

Spec: §7.6.2.1.1, p. 51 — “service_instance_name string<256> PID_SERVICE_INSTANCE_NAME 0x0080”.

Repo: crates/rtps/src/parameter_list.rs (pid::SERVICE_INSTANCE_NAME), crates/rtps/src/publication_data.rs (PublicationBuiltinTopicData::service_instance_name, codec), crates/dcps/src/runtime.rs::RpcDiscoveryExt::check (bound 256)

Tests: crates/rtps/src/parameter_list.rs::tests::rpc_pid_constants_match_spec, crates/rtps/src/publication_data.rs::tests::rpc_discovery_pids_roundtrip, crates/dcps/tests/rpc_discovery_extension.rs::a_discovery_string_longer_than_256_is_refused

Status: done — PID 0x0080 with a CDR string; DataWriter::set_rpc_discovery and DataReader::set_rpc_discovery refuse a name over 256 characters (DdsError::BadParameter). PID and codec b5224bd70dbb, announcement and bound 211d416cdda3. The decoder does not check the bound on a received announcement.

Spec: §7.6.2.1.1, p. 51 — “related_datareader_key GUID_t PID_RELATED_ENTITY_GUID 0x0081”.

Repo: crates/rtps/src/parameter_list.rs (pid::RELATED_ENTITY_GUID), crates/rtps/src/publication_data.rs (PublicationBuiltinTopicData::related_entity_guid), crates/rtps/src/subscription_data.rs (the same field, §7.6.2.1.2)

Tests: crates/rtps/src/parameter_list.rs::tests::rpc_pid_constants_match_spec, crates/rtps/src/publication_data.rs::tests::rpc_discovery_pids_roundtrip, crates/rtps/src/subscription_data.rs::tests::rpc_discovery_pids_roundtrip_subscription

Status: done — PID 0x0081 with a 16-octet GUID; the field is named related_entity_guid and carries related_datareader_key of a publication and related_datawriter_key of a subscription. b5224bd70dbb.

§7.6.2.1.1 topic_aliases with PID 0x0082

Spec: §7.6.2.1.1, p. 51 — “topic_aliases sequence<string<256>> PID_TOPIC_ALIASES 0x0082”.

Repo: crates/rtps/src/parameter_list.rs (pid::TOPIC_ALIASES), crates/rtps/src/publication_data.rs (PublicationBuiltinTopicData::topic_aliases), crates/dcps/src/runtime.rs::RpcDiscoveryExt::check (bound 256 per alias)

Tests: crates/rtps/src/parameter_list.rs::tests::rpc_pids_roundtrip_in_parameter_list, crates/rtps/src/publication_data.rs::tests::rpc_discovery_pids_roundtrip, crates/dcps/tests/topic_alias_matching.rs::a_reader_on_an_alias_matches_the_writer_over_the_wire

Status: done — PID 0x0082 with a sequence of strings; set_rpc_discovery refuses an alias over 256 characters, and the matching of endpoints uses the aliases (bdf9ab1e6caa; PID b5224bd70dbb, announcement 211d416cdda3).

§7.6.2.1.1 PublicationBuiltinTopicDataExt

Spec: §7.6.2.1.1, p. 51 — “@extensibility(MUTABLE_EXTENSIBILITY) struct PublicationBuiltinTopicDataExt : PublicationBuiltinTopicData { @ID(0x0080) string<256> service_instance_name; @ID(0x0081) GUID_t related_datareader_key; @ID(0x0082) sequence<string<256>> topic_aliases; };”

Repo: crates/rtps/src/publication_data.rs::PublicationBuiltinTopicData (the three members as optional parameters of the ParameterList), crates/dcps/src/runtime.rs::RpcDiscoveryExt

Tests: crates/rtps/src/publication_data.rs::tests::rpc_discovery_pids_roundtrip, crates/rtps/src/publication_data.rs::tests::rpc_pids_optional_legacy_peer_parses_ok, crates/dcps/tests/rpc_discovery_extension.rs::the_rpc_extension_of_a_writer_and_a_reader_reaches_the_matched_peer

Status: done — the wire carries the three members; a peer without the parameters is read, the members are then None. The type PublicationBuiltinTopicDataExt with the member names of the spec is in crates/rpc (next item). b5224bd70dbb, 211d416cdda3.

§7.6.2.1.1 Type PublicationBuiltinTopicDataExt in crates/rpc

Spec: §7.6.2.1.1, p. 51 — as above.

Repo: crates/rpc/src/discovery_ext.rs::PublicationBuiltinTopicDataExt and SubscriptionBuiltinTopicDataExt (announcement, from_peer)

Tests: crates/rpc/src/discovery_ext.rs::tests::the_extension_carries_the_three_members_of_the_spec, crates/rpc/src/discovery_ext.rs::tests::an_absent_related_key_reads_as_guid_unknown

Status: done — the types have the members of the spec (service_instance_name, related_datareader_key or related_datawriter_key, topic_aliases); service_name and mapping_profile are removed. announcement() converts them into the announcement of crates/dcps. Requester and Replier build RpcDiscoveryExt directly with the same three members and do not use these types (e305669e2c42).

§7.6.2.1.1 service_instance_name: instance name at the service

Spec: §7.6.2.1.1, p. 52 — “The service_instance_name is the instance name specified by the user at the service-side. If none is specified, there is no default value.”

Repo: crates/rpc/src/replier.rs::Replier::from_topics (name only if one is given), crates/rpc/src/endpoint.rs::RpcEndpointBuilder::instance_name, runtime/cpp/include/dds/rpc.hpp, runtime/java/src/main/java/org/zerodds/ddsrpc/ReplierImpl.java

Tests: crates/rpc-rust-e2e/tests/enhanced_e2e.rs::the_client_waits_for_the_service_instance_it_names, crates/rpc-rust-e2e/tests/evolution_styles_discovery.rs::the_runtime_announces_aliases_the_instance_name_and_the_related_keys, crates/rpc-rust-e2e/tests/evolution_styles_discovery.rs::a_service_without_an_instance_name_or_parents_announces_neither, crates/rpc/src/endpoint.rs::tests::instance_name_propagated_to_both_sides, crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together (rpc_runtime_roundtrip.cpp, check_instance_addressing)

Status: done — Rust (e305669e2c42, tests 32972ee16bdd, 414e077c527d) and C++ (17a3aef74360) announce the name at the service endpoints when the user gives one; without a name nothing is announced (a test exists for this). In C++ an Enhanced request bound to an instance reaches only the readers that announced that name (6289b73b7853). crates/java-omgdds writes and reads PIDs 0x0080 to 0x0082 (rtps/RpcDiscovery.java, DiscoveryData.buildEndpoint and parseEndpoint, bound string<256>: an announcement beyond it is refused as in the decoder of crates/rtps; f65fb3965b5e). ZeroDdsParticipant announces service_instance_name on the endpoints of the service and related_*_key on both sides (9993349aff89). Tests: crates/java-omgdds/java/src/test/java/org/zerodds/rtps/RpcDiscoveryTest.java (theThreeParametersTravelWithTheEndpoint, aStringBeyondTheBoundIsRefused, aTopicCorrespondsByNameOrByAlias). The Java runtime applies the matching rule from the announced endpoints (1fddccd2b87b): ReplierImpl holds back the requests of a client whose reply reader the reply writer does not know (Figure 7.3, per client); RequesterImpl sends when the instance’s request reader names a reply writer that the reply reader has discovered (Figure 7.4). An endpoint without an announcement and a binding without discovery data keep the match by topic. Test: crates/rpc/tests/java/RpcRuntimeRoundtrip.java::overTheJavaPsm through crates/rpc/tests/java_rpc_runtime.rs::the_java_rpc_runtime_and_the_generated_services_run_together (needs a JDK; not run on the Mac or on the Linux test host).

§7.6.2.1.1 Client DataWriter without service_instance_name

Spec: §7.6.2.1.1, p. 52 — “Likewise, the client-side DataWriter shall not include service_instance_name.”

Repo: crates/rpc/src/requester.rs::Requester::from_topics (service_instance_name: None), crates/rpc/src/endpoint.rs::RpcEndpointBuilder::publication (service side only)

Tests: crates/rpc/src/endpoint.rs::tests::instance_name_propagated_to_both_sides (checks the builder; the test’s name comes from the earlier behaviour), crates/rpc-rust-e2e/tests/enhanced_e2e.rs::the_client_waits_for_the_service_instance_it_names, crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together

Status: done — the client writer announces no service_instance_name, in Rust, C++ (test: request_writer.has_instance_name is false) and Java (the client gets no name). 973def296a10 (builder), e305669e2c42 (runtime). No Rust test reads the announcement of a Requester back from the peer.

§7.6.2.1.1 topic_aliases by §7.4.3, without default

Spec: §7.6.2.1.1, p. 52 — “The topic_aliases are as per defined in 7.4.3 The Enhanced Service Mapping. There is no default value.”

Repo: crates/rpc/src/requester.rs::Requester::from_topics, crates/rpc/src/replier.rs::Replier::from_topics (aliases from ServiceTopicNames::request_aliases and reply_aliases), crates/rpc/src/endpoint.rs::RpcEndpointBuilder::aliases

Tests: crates/rpc/src/topic_naming.rs::tests::every_parent_interface_contributes_one_alias, crates/rpc/src/endpoint.rs::tests::the_parent_interfaces_are_announced_as_topic_aliases, crates/rpc/src/endpoint.rs::tests::topic_aliases_empty_yields_none, crates/rpc-rust-e2e/tests/evolution_styles_discovery.rs::the_runtime_announces_aliases_the_instance_name_and_the_related_keys, crates/rpc-rust-e2e/tests/evolution_styles_discovery.rs::a_service_without_an_instance_name_or_parents_announces_neither, crates/dcps/tests/rpc_discovery_extension.rs::the_rpc_extension_of_a_writer_and_a_reader_reaches_the_matched_peer, crates/rpc-rust-e2e/tests/java_peer.rs::a_java_client_calls_a_rust_service, crates/rpc-rust-e2e/tests/java_peer.rs::a_rust_client_calls_a_java_service, crates/rpc-rust-e2e/tests/java_peer.rs::a_java_client_of_the_base_calls_a_rust_service_of_the_derived_interface, crates/rpc-rust-e2e/tests/java_peer.rs::a_rust_client_of_the_base_calls_a_java_service_of_the_derived_interface

Status: done — Rust (e305669e2c42) and C++ announce the aliases of the parents (§7.4.3), nothing without parents and without an entry. A running Requester and Replier announce the aliases, the peer reads them; without parents the field stays empty (tests above, 32972ee16bdd, 414e077c527d). Java announces the aliases the parents of the params give (PID 0x0082 on the wire: RpcDiscoveryTest.java::theThreeParametersTravelWithTheEndpoint, f65fb3965b5e, 9993349aff89); the generated Java binding sets parents for a derived interface (400433a9d00a). The Java PSM matches over the aliases and pairs the types by assignability (2d0f809c6e2); measured with a Java client of the base against a Rust service of the derived interface and the other way round (item for §7.4.3, Java).

Spec: §7.6.2.1.1, p. 52 — “When not present the default value for the related_datareader_key shall be interpreted as GUID_UNKNOWN as defined by sub clause 9.3.1.5 of the [RTPS] specification.”

Repo: crates/rpc/src/discovery_ext.rs::GUID_UNKNOWN and from_peer, crates/rtps/src/publication_data.rs (the decoder returns None)

Tests: crates/rpc/src/discovery_ext.rs::tests::an_absent_related_key_reads_as_guid_unknown, crates/rpc/src/discovery_ext.rs::tests::an_unannounced_service_completes_only_when_accepted, crates/rtps/src/publication_data.rs::tests::rpc_pids_optional_legacy_peer_parses_ok

Status: done — an absent key reads as GUID_UNKNOWN (16 zeros); the matching functions treat it as not named, a pair without naming is complete only with accept_unannounced (e305669e2c42).

Spec: §7.6.2.1.1, p. 52 — “The PublicationBuiltinTopicDataExt that corresponds to the client-side DataWriter used for sending requests for a service shall have the related_datareader_key set to the BuiltinTopicKey_t of the client-side DataReader used for receiving the replies.”

Repo: crates/rpc/src/requester.rs::Requester::from_topics (set_rpc_discovery on the request writer with the GUID of the reply reader), crates/rpc/src/endpoint.rs::RpcEndpointBuilder::build_requester

Tests: crates/rpc/src/endpoint.rs::tests::requester_related_entity_guids_cross_link, crates/rpc-rust-e2e/tests/evolution_styles_discovery.rs::the_runtime_announces_aliases_the_instance_name_and_the_related_keys, crates/rpc-rust-e2e/tests/enhanced_e2e.rs::the_client_waits_for_the_service_instance_it_names, crates/zerodds-c-api/tests/rpc_discovery.rs::the_extension_is_announced_read_and_decides_the_matching

Status: done — Rust (e305669e2c42) and C++ (17a3aef74360) set the key at the client writer to the reply reader and vice versa. The Rust test the_runtime_announces_aliases_the_instance_name_and_the_related_keys reads the keys at the peers of a running Requester and Replier (32972ee16bdd, 414e077c527d). crates/java-omgdds writes and reads PIDs 0x0080 to 0x0082 (rtps/RpcDiscovery.java, DiscoveryData.buildEndpoint and parseEndpoint, bound string<256>: an announcement beyond it is refused as in the decoder of crates/rtps; f65fb3965b5e). ZeroDdsParticipant announces service_instance_name on the endpoints of the service and related_*_key on both sides (9993349aff89). Tests: crates/java-omgdds/java/src/test/java/org/zerodds/rtps/RpcDiscoveryTest.java (theThreeParametersTravelWithTheEndpoint, aStringBeyondTheBoundIsRefused, aTopicCorrespondsByNameOrByAlias). The Java runtime applies the matching rule from the announced endpoints (1fddccd2b87b): ReplierImpl holds back the requests of a client whose reply reader the reply writer does not know (Figure 7.3, per client); RequesterImpl sends when the instance’s request reader names a reply writer that the reply reader has discovered (Figure 7.4). An endpoint without an announcement and a binding without discovery data keep the match by topic. Test: crates/rpc/tests/java/RpcRuntimeRoundtrip.java::overTheJavaPsm through crates/rpc/tests/java_rpc_runtime.rs::the_java_rpc_runtime_and_the_generated_services_run_together (needs a JDK; not run on the Mac or on the Linux test host).

Spec: §7.6.2.1.1, p. 52 — “The PublicationBuiltinTopicDataExt that corresponds to the service-side DataWriter used for sending replies shall have the related_datareader_key set to the BuiltinTopicKey_t of the service-side DataReader used to receive the requests.”

Repo: crates/rpc/src/replier.rs::Replier::from_topics (set_rpc_discovery on the reply writer with the GUID of the request reader), crates/rpc/src/endpoint.rs::RpcEndpointBuilder::build_replier

Tests: crates/rpc/src/endpoint.rs::tests::replier_related_entity_guids_cross_link, crates/rpc-rust-e2e/tests/enhanced_e2e.rs::the_client_waits_for_the_service_instance_it_names, crates/zerodds-c-api/tests/rpc_discovery.rs::the_extension_is_announced_read_and_decides_the_matching, crates/rpc-rust-e2e/tests/evolution_styles_discovery.rs::the_runtime_announces_aliases_the_instance_name_and_the_related_keys

Status: done — Rust (e305669e2c42) and C++ (17a3aef74360) set the key on the service writer to the request reader and the other way round. For Rust a test reads the announcement of the Replier at the other side: related_entity_guid of the reply writer is the GUID of the request reader (414e077c527d). crates/java-omgdds writes and reads PIDs 0x0080 to 0x0082 (rtps/RpcDiscovery.java, DiscoveryData.buildEndpoint and parseEndpoint, bound string<256>: an announcement beyond it is refused as in the decoder of crates/rtps; f65fb3965b5e). ZeroDdsParticipant announces service_instance_name on the endpoints of the service and related_*_key on both sides (9993349aff89). Tests: crates/java-omgdds/java/src/test/java/org/zerodds/rtps/RpcDiscoveryTest.java (theThreeParametersTravelWithTheEndpoint, aStringBeyondTheBoundIsRefused, aTopicCorrespondsByNameOrByAlias). The Java runtime applies the matching rule from the announced endpoints (1fddccd2b87b): ReplierImpl holds back the requests of a client whose reply reader the reply writer does not know (Figure 7.3, per client); RequesterImpl sends when the instance’s request reader names a reply writer that the reply reader has discovered (Figure 7.4). An endpoint without an announcement and a binding without discovery data keep the match by topic. Test: crates/rpc/tests/java/RpcRuntimeRoundtrip.java::overTheJavaPsm through crates/rpc/tests/java_rpc_runtime.rs::the_java_rpc_runtime_and_the_generated_services_run_together (needs a JDK; not run on the Mac or on the Linux test host).

§7.6.2.1.2 service_instance_name with PID 0x0080

Spec: §7.6.2.1.2, p. 52 — “service_instance_name string<256> PID_SERVICE_INSTANCE_NAME 0x0080”.

Repo: crates/rtps/src/parameter_list.rs (pid::SERVICE_INSTANCE_NAME); crates/rtps/src/subscription_data.rs (SubscriptionBuiltinTopicData::service_instance_name, codec in to_pl_cdr_le and from_pl_cdr_le); crates/dcps/src/subscriber.rs (DataReader::set_rpc_discovery, DataReader::matched_rpc_writers) with RpcDiscoveryExt in crates/dcps/src/runtime.rs

Tests: crates/rtps/src/subscription_data.rs::tests::rpc_discovery_pids_roundtrip_subscription, crates/rtps/src/parameter_list.rs::tests::rpc_pid_constants_match_spec, crates/dcps/tests/rpc_discovery_extension.rs::the_rpc_extension_of_a_writer_and_a_reader_reaches_the_matched_peer (Linux only)

Status: done — PID 0x0080 is encoded, decoded and announced by the DataReader (codec b5224bd70dbb, announcement 211d416cdda3). RpcDiscoveryExt::check (crates/dcps/src/runtime.rs) refuses a string over 256 on announcing (test: crates/dcps/tests/rpc_discovery_extension.rs::a_discovery_string_longer_than_256_is_refused). The decoder in crates/rtps rejects a value over 256 with WireError::ValueOutOfRange (ae5fededca89; test: crates/rtps/src/subscription_data.rs::tests::a_discovery_string_beyond_the_bound_is_refused_subscription).

Spec: §7.6.2.1.2, p. 52 — “related_datawriter_key GUID_t PID_RELATED_ENTITY_GUID 0x0081”.

Repo: crates/rtps/src/parameter_list.rs (pid::RELATED_ENTITY_GUID); crates/rtps/src/subscription_data.rs (SubscriptionBuiltinTopicData::related_entity_guid, codec in to_pl_cdr_le and from_pl_cdr_le); crates/dcps/src/subscriber.rs (DataReader::set_rpc_discovery, DataReader::matched_rpc_writers) with RpcDiscoveryExt in crates/dcps/src/runtime.rs

Tests: crates/rtps/src/subscription_data.rs::tests::rpc_discovery_pids_roundtrip_subscription, crates/rtps/src/parameter_list.rs::tests::rpc_pid_constants_match_spec, crates/dcps/tests/rpc_discovery_extension.rs::the_rpc_extension_of_a_writer_and_a_reader_reaches_the_matched_peer (Linux only)

Status: done — PID 0x0081 (PID_RELATED_ENTITY_GUID) is encoded, decoded and announced (codec b5224bd70dbb, announcement 211d416cdda3). The field is named related_entity_guid in the code; on a DataReader it is the related_datawriter_key.

§7.6.2.1.2 topic_aliases with PID 0x0082

Spec: §7.6.2.1.2, p. 52 — “topic_aliases sequence<string<256>> PID_TOPIC_ALIASES 0x0082”.

Repo: crates/rtps/src/parameter_list.rs (pid::TOPIC_ALIASES); crates/rtps/src/subscription_data.rs (SubscriptionBuiltinTopicData::topic_aliases, codec in to_pl_cdr_le and from_pl_cdr_le); crates/dcps/src/subscriber.rs (DataReader::set_rpc_discovery, DataReader::matched_rpc_writers) with RpcDiscoveryExt in crates/dcps/src/runtime.rs

Tests: crates/rtps/src/subscription_data.rs::tests::rpc_discovery_pids_roundtrip_subscription, crates/rtps/src/parameter_list.rs::tests::rpc_pid_constants_match_spec, crates/dcps/tests/rpc_discovery_extension.rs::the_rpc_extension_of_a_writer_and_a_reader_reaches_the_matched_peer (Linux only)

Status: done — PID 0x0082 is encoded (sequence of strings), decoded and announced (codec b5224bd70dbb, announcement 211d416cdda3). Matching by alias is under the item on §7.4.3.

§7.6.2.1.2 SubscriptionBuiltinTopicDataExt

Spec: §7.6.2.1.2, p. 52 — “@extensibility(MUTABLE_EXTENSIBILITY) struct SubscriptionBuiltinTopicDataExt : SubscriptionBuiltinTopicData { @ID(0x0080) string<256> service_instance_name; @ID(0x0081) GUID_t related_datawriter_key; @ID(0x0082) sequence<string<256>> topic_aliases; };”

Repo: crates/rtps/src/subscription_data.rs::SubscriptionBuiltinTopicData (wire); crates/rpc/src/discovery_ext.rs::SubscriptionBuiltinTopicDataExt (data model with the three members of the spec, announcement and from_peer to zerodds_dcps::runtime::RpcDiscoveryExt)

Tests: crates/rtps/src/subscription_data.rs::tests::rpc_discovery_pids_roundtrip_subscription, crates/rtps/src/subscription_data.rs::tests::rpc_pids_optional_legacy_subscription_parses_ok, crates/rpc/src/discovery_ext.rs::tests::the_extension_carries_the_three_members_of_the_spec

Status: done — the type in crates/rpc has the three members of the spec (service_instance_name, related_datawriter_key, topic_aliases); on the wire they are parameters 0x0080 to 0x0082 of the parameter list (type in crates/rpc e305669e2c42, wire b5224bd70dbb). An endpoint without the parameters is read and yields None or GUID_UNKNOWN.

§7.6.2.1.2 service_instance_name: instance name at the service

Spec: §7.6.2.1.2, p. 52 — “The service_instance_name is the instance name specified by the user at the service-side. If none is specified, there is no default value.”

Repo: crates/rpc/src/replier.rs::Replier::with_options (Enhanced: the instance name goes to the request reader and the reply writer; without a name the value is absent); crates/rpc/src/endpoint.rs::RpcEndpointBuilder::instance_name

Tests: crates/rpc/src/endpoint.rs::tests::instance_name_propagated_to_both_sides, crates/rpc-rust-e2e/tests/enhanced_e2e.rs::the_client_waits_for_the_service_instance_it_names

Status: done — the service announces the name the user set, None without a name (e305669e2c42). The test shows that the client reaches only the instance whose name it carries. C++ announces the same value (17a3aef74360; test: crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together). For Java see the item “§7.6.2.1 announcement of the extensions by the runtimes”.

§7.6.2.1.2 Client DataReader without service_instance_name

Spec: §7.6.2.1.2, p. 52 — “Likewise, the client-side DataReader shall not include service_instance_name.”

Repo: crates/rpc/src/requester.rs::Requester::with_options (Enhanced: service_instance_name: None on the request writer and the reply reader); crates/rpc/src/endpoint.rs::RpcEndpointBuilder (973def296a10)

Tests: crates/rpc/src/endpoint.rs::tests::instance_name_propagated_to_both_sides (builder); C++: crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together, crates/rpc-rust-e2e/tests/evolution_styles_discovery.rs::the_runtime_announces_aliases_the_instance_name_and_the_related_keys

Status: done — the requester’s reply reader announces no name in Rust (e305669e2c42), in C++ (17a3aef74360) and in the builder (973def296a10). For Rust a test reads the announcement of Requester and Replier at the other side (matched_rpc_readers, matched_rpc_writers): the client’s endpoints carry service_instance_name: None (414e077c527d). crates/java-omgdds writes and reads PIDs 0x0080 to 0x0082 (rtps/RpcDiscovery.java, DiscoveryData.buildEndpoint and parseEndpoint, bound string<256>: an announcement beyond it is refused as in the decoder of crates/rtps; f65fb3965b5e). ZeroDdsParticipant announces service_instance_name on the endpoints of the service and related_*_key on both sides (9993349aff89). Tests: crates/java-omgdds/java/src/test/java/org/zerodds/rtps/RpcDiscoveryTest.java (theThreeParametersTravelWithTheEndpoint, aStringBeyondTheBoundIsRefused, aTopicCorrespondsByNameOrByAlias). The Java runtime applies the matching rule from the announced endpoints (1fddccd2b87b): ReplierImpl holds back the requests of a client whose reply reader the reply writer does not know (Figure 7.3, per client); RequesterImpl sends when the instance’s request reader names a reply writer that the reply reader has discovered (Figure 7.4). An endpoint without an announcement and a binding without discovery data keep the match by topic. Test: crates/rpc/tests/java/RpcRuntimeRoundtrip.java::overTheJavaPsm through crates/rpc/tests/java_rpc_runtime.rs::the_java_rpc_runtime_and_the_generated_services_run_together (needs a JDK; not run on the Mac or on the Linux test host).

§7.6.2.1.2 topic_aliases by §7.4.3, without default

Spec: §7.6.2.1.2, p. 52 — “The topic_aliases are as per defined in sub clause 7.4.3. There is no default value.”

Repo: crates/rpc/src/requester.rs::Requester::with_options and crates/rpc/src/replier.rs::Replier::with_options (aliases from ServiceTopicNames::request_aliases and reply_aliases, None without aliases); crates/rpc/src/endpoint.rs::RpcEndpointBuilder (aliases); crates/dcps/src/runtime.rs (matching by alias)

Tests: crates/rpc/src/endpoint.rs::tests::topic_aliases_propagated_to_both_sides, crates/dcps/tests/topic_alias_matching.rs (Linux only), crates/dcps/tests/rpc_discovery_extension.rs::the_rpc_extension_of_a_writer_and_a_reader_reaches_the_matched_peer, crates/rpc/tests/language_binding_agreement.rs (names of the aliases); C++: crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together, crates/rpc-rust-e2e/tests/evolution_styles_discovery.rs::the_runtime_announces_aliases_the_instance_name_and_the_related_keys, crates/rpc-rust-e2e/tests/evolution_styles_discovery.rs::a_service_without_an_instance_name_or_parents_announces_neither, crates/rpc-rust-e2e/tests/java_peer.rs::a_java_client_calls_a_rust_service, crates/rpc-rust-e2e/tests/java_peer.rs::a_rust_client_calls_a_java_service, crates/rpc-rust-e2e/tests/java_peer.rs::a_java_client_of_the_base_calls_a_rust_service_of_the_derived_interface, crates/rpc-rust-e2e/tests/java_peer.rs::a_rust_client_of_the_base_calls_a_java_service_of_the_derived_interface

Status: done — the aliases go on the wire for inheritance (Rust e305669e2c42, C++ 17a3aef74360) and let endpoints match (bdf9ab1e6caa); without aliases nothing is announced. For Rust a test reads the aliases of Requester and Replier at the other side (robot_Base_Service_Request and robot_Base_Service_Reply) and checks that a service without a base announces none (414e077c527d). Java announces the aliases the parents of the params give (f65fb3965b5e, 9993349aff89); the generated Java binding sets parents for a derived interface (400433a9d00a). The Java PSM matches over the aliases and pairs the types by assignability (2d0f809c6e2); measured with a Java client of the base against a Rust service of the derived interface and the other way round (item for §7.4.3, Java).

Spec: §7.6.2.1.2, p. 53 — “When not present the default value for the related_datareader_key shall be interpreted as GUID_UNKNOWN as defined by sub clause 9.3.1.5 of the [RTPS] specification.”

Repo: crates/rpc/src/discovery_ext.rs::SubscriptionBuiltinTopicDataExt::from_peer (GUID_UNKNOWN); crates/rtps/src/subscription_data.rs (the decoder yields None)

Tests: crates/rtps/src/subscription_data.rs::tests::rpc_pids_optional_legacy_subscription_parses_ok, crates/rpc/src/discovery_ext.rs::tests::an_absent_related_key_reads_as_guid_unknown, crates/rpc/src/discovery_ext.rs::tests::an_unannounced_service_completes_only_when_accepted

Status: done — an absent parameter 0x0081 reads as GUID_UNKNOWN (e305669e2c42). The clause of the spec on the subscription names related_datareader_key here.

Spec: §7.6.2.1.2, p. 53 — “The SubscriptionBuiltinTopicDataExt that corresponds to the client-side DataReader used to receive replies shall have the related_datawriter_key set to the BuiltinTopicKey_t of the client-side DataWriter used to send the requests to the DDS-RPC Service.”

Repo: crates/rpc/src/requester.rs::Requester::with_options (the reply reader names the request writer); crates/rpc/src/endpoint.rs::RpcEndpointBuilder::build_requester

Tests: crates/rpc-rust-e2e/tests/enhanced_e2e.rs::an_enhanced_call_is_answered_through_the_related_sample_identity, crates/rpc/src/endpoint.rs::tests::requester_related_entity_guids_cross_link, crates/rpc/src/discovery_ext.rs::tests::the_service_unmasks_a_client_once_both_its_endpoints_are_discovered

Status: done — Rust e305669e2c42, C++ 17a3aef74360. The call in the first test is answered only if the service can assign the client’s reply reader to the request writer through related_datawriter_key (client_matching_complete, default ClientMatching::Hold).

Spec: §7.6.2.1.2, p. 53 — “The SubscriptionBuiltinTopicDataExt that corresponds to the service-side DataReader used to write replies shall have the related_datawriter_key set to the BuiltinTopicKey_t of the service-side DataWriter used to receive requests.”

Repo: crates/rpc/src/replier.rs::Replier::with_options (the request reader names the reply writer); crates/rpc/src/endpoint.rs::RpcEndpointBuilder::build_replier

Tests: crates/rpc-rust-e2e/tests/enhanced_e2e.rs::the_client_waits_for_the_service_instance_it_names, crates/rpc/src/endpoint.rs::tests::replier_related_entity_guids_cross_link, crates/rpc/src/discovery_ext.rs::tests::the_two_endpoints_must_name_each_other

Status: done — Rust e305669e2c42, C++ 17a3aef74360. The sentence of the spec swaps the roles (“DataReader used to write replies”, “DataWriter used to receive requests”); the request reader names the reply writer, as Figure 7.4 requires. service_matching_complete holds only if request reader and reply writer name each other (tests 1 and 3).

§7.6.2.1 announcement of the extensions by the runtimes

Spec: §7.6.2.1.1 and §7.6.2.1.2, pp. 51–53 — as the items above.

Repo: crates/dcps/src/publisher.rs and crates/dcps/src/subscriber.rs (set_rpc_discovery, matched_rpc_readers, matched_rpc_writers); crates/rpc/src/requester.rs::Requester::with_options and crates/rpc/src/replier.rs::Replier::with_options (Enhanced); C++: runtime/cpp/include/dds/rpc.hpp (announce_rpc_discovery) and runtime/cpp/include/dds/rpc/zerodds.hpp through zerodds_writer_set_rpc_discovery and zerodds_reader_set_rpc_discovery (crates/zerodds-c-api/src/rpc_discovery_ffi.rs)

Tests: crates/dcps/tests/rpc_discovery_extension.rs::the_rpc_extension_of_a_writer_and_a_reader_reaches_the_matched_peer (Linux only), crates/zerodds-c-api/tests/rpc_discovery.rs::the_extension_is_announced_read_and_decides_the_matching, crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together, crates/rpc-rust-e2e/tests/enhanced_e2e.rs::the_client_waits_for_the_service_instance_it_names, crates/rpc-rust-e2e/tests/evolution_styles_discovery.rs::the_runtime_announces_aliases_the_instance_name_and_the_related_keys, crates/rpc-rust-e2e/tests/evolution_styles_discovery.rs::a_service_without_an_instance_name_or_parents_announces_neither, crates/rpc-rust-e2e/tests/java_peer.rs::a_java_client_calls_a_rust_service, crates/rpc-rust-e2e/tests/java_peer.rs::a_rust_client_calls_a_java_service, crates/rpc-rust-e2e/tests/java_peer.rs::a_java_client_of_the_base_calls_a_rust_service_of_the_derived_interface, crates/rpc-rust-e2e/tests/java_peer.rs::a_rust_client_of_the_base_calls_a_java_service_of_the_derived_interface

Status: done — Rust, C++ and Java announce service_instance_name, related_*_key and topic_aliases of their endpoints and read them at discovered endpoints (dcps 211d416cdda3, Rust e305669e2c42, C++ 17a3aef74360, Java f65fb3965b5e and 9993349aff89); the bound 256 is checked by RpcDiscoveryExt::check when announcing, the decoders in crates/rtps and in crates/java-omgdds refuse values beyond it (ae5fededca89, f65fb3965b5e). For Rust a test reads the announcement of Requester and Replier at the other side (414e077c527d), for Java RpcDiscoveryTest.java. The generated Java binding sets the aliases of a derived interface (400433a9d00a); a Java peer against a Rust peer reads the announcement (dbb935492284). The Java PSM matches over the aliases it reads and pairs by assignability (2d0f809c6e2), measured against Rust peers in both directions (item for §7.4.3, Java).

§7.6.2.2 Additional rules for client writer and service reader

Spec: §7.6.2.2, p. 53 — “Additional rules shall be used at the client-side DataWriter and service-side DataReader”.

Repo: —

Tests: —

Status: n/a (informative) — introduction; the rules follow as items.

§7.6.2.2 Client writer sends only after the match of the reply writer

Spec: §7.6.2.2, p. 53 — “The client-side DataWriter (request DataWriter) shall not send out any request to a service DataReader unless the client-side DataReader (reply DataReader) has discovered and matched the corresponding service DataWriter (reply DataWriter).”

Repo: crates/rpc/src/requester.rs::Requester::service_matched and Requester::wait_for_service (Enhanced); crates/rpc/src/discovery_ext.rs::service_matching_complete; C++: runtime/cpp/include/dds/rpc.hpp (Requester::wait_for_service, DataWriter::service_matching_complete); Java: runtime/java/src/main/java/org/zerodds/ddsrpc/RequesterImpl.java

Tests: crates/rpc/src/requester.rs::tests::an_enhanced_request_waits_for_the_service_and_fails_without_sending, crates/rpc/src/requester.rs::tests::the_fail_setting_does_not_wait, crates/rpc/src/requester.rs::tests::the_basic_mapping_sends_without_a_service_match, crates/rpc-rust-e2e/tests/enhanced_e2e.rs::the_client_waits_for_the_service_instance_it_names, crates/rpc/src/discovery_ext.rs::tests::the_client_waits_for_both_service_endpoints, crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together, crates/rpc/tests/java_rpc_runtime.rs::the_java_rpc_runtime_and_the_generated_services_run_together

Status: done — Rust (e305669e2c42) and C++ (4b6b049312ff, 17a3aef74360): the request goes out only when the service’s request reader and reply writer are discovered and name each other. The Rust call holds the request for at most the request_timeout of the QoS and then ends with RpcError::ServiceNotMatched without having sent (ServiceMatching::Queue; Fail and Off are the named alternatives). The Basic mapping does not have the rule (§7.6.1). crates/java-omgdds writes and reads PIDs 0x0080 to 0x0082 (rtps/RpcDiscovery.java, DiscoveryData.buildEndpoint and parseEndpoint, bound string<256>: an announcement beyond it is refused as in the decoder of crates/rtps; f65fb3965b5e). ZeroDdsParticipant announces service_instance_name on the endpoints of the service and related_*_key on both sides (9993349aff89). Tests: crates/java-omgdds/java/src/test/java/org/zerodds/rtps/RpcDiscoveryTest.java (theThreeParametersTravelWithTheEndpoint, aStringBeyondTheBoundIsRefused, aTopicCorrespondsByNameOrByAlias). The Java runtime applies the matching rule from the announced endpoints (1fddccd2b87b): ReplierImpl holds back the requests of a client whose reply reader the reply writer does not know (Figure 7.3, per client); RequesterImpl sends when the instance’s request reader names a reply writer that the reply reader has discovered (Figure 7.4). An endpoint without an announcement and a binding without discovery data keep the match by topic. Test: crates/rpc/tests/java/RpcRuntimeRoundtrip.java::overTheJavaPsm through crates/rpc/tests/java_rpc_runtime.rs::the_java_rpc_runtime_and_the_generated_services_run_together (needs a JDK; not run on the Mac or on the Linux test host).

§7.6.2.2 Service reader rejects requests before the match

Spec: §7.6.2.2, p. 53 — “The service-side DataReader (request DataReader) shall reject requests from a client DataWriter (request DataWriter) as long as the service-side DataWriter (reply DataWriter) has not discovered and matched the corresponding client-side DataReader (reply DataReader).”

Repo: crates/rpc/src/replier.rs::Replier::take_enhanced_requests (holds requests of a client that is not completely discovered); crates/rpc/src/discovery_ext.rs::client_matching_complete; C++: runtime/cpp/include/dds/rpc.hpp (Replier, DataReader::client_matching_complete); Java: runtime/java/src/main/java/org/zerodds/ddsrpc/ReplierImpl.java

Tests: crates/rpc/src/replier.rs::tests::an_enhanced_request_of_an_undiscovered_client_is_held, crates/rpc/src/replier.rs::tests::the_named_alternatives_release_a_request_of_an_undiscovered_client, crates/rpc/src/discovery_ext.rs::tests::the_service_unmasks_a_client_once_both_its_endpoints_are_discovered, crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together, crates/rpc/tests/java_rpc_runtime.rs::the_java_rpc_runtime_and_the_generated_services_run_together

Status: done — Rust (e305669e2c42) and C++ (4b6b049312ff, 17a3aef74360): the service processes no request of a client whose reply reader the reply writer has not discovered. Rust holds the request (up to HELD_REQUESTS_MAX = 4096, the overflow is counted in held_overflow()) and processes it once the client is complete instead of discarding it. The Basic mapping does not have the rule. crates/java-omgdds writes and reads PIDs 0x0080 to 0x0082 (rtps/RpcDiscovery.java, DiscoveryData.buildEndpoint and parseEndpoint, bound string<256>: an announcement beyond it is refused as in the decoder of crates/rtps; f65fb3965b5e). ZeroDdsParticipant announces service_instance_name on the endpoints of the service and related_*_key on both sides (9993349aff89). Tests: crates/java-omgdds/java/src/test/java/org/zerodds/rtps/RpcDiscoveryTest.java (theThreeParametersTravelWithTheEndpoint, aStringBeyondTheBoundIsRefused, aTopicCorrespondsByNameOrByAlias). The Java runtime applies the matching rule from the announced endpoints (1fddccd2b87b): ReplierImpl holds back the requests of a client whose reply reader the reply writer does not know (Figure 7.3, per client); RequesterImpl sends when the instance’s request reader names a reply writer that the reply reader has discovered (Figure 7.4). An endpoint without an announcement and a binding without discovery data keep the match by topic. Test: crates/rpc/tests/java/RpcRuntimeRoundtrip.java::overTheJavaPsm through crates/rpc/tests/java_rpc_runtime.rs::the_java_rpc_runtime_and_the_generated_services_run_together (needs a JDK; not run on the Mac or on the Linux test host).

§7.6.2.2 Implementation outside the DDS layer admissible

Spec: §7.6.2.2, p. 53 — “The above rules may be implemented outside “DDS layer” because no discovery algorithm modifications are required in the underlying DDS implementation”.

Repo: —

Tests: —

Status: n/a (informative) — permission.

§7.6.2.2.1 Client matching at the service: no requests until complete

Spec: §7.6.2.2.1, p. 54 — ““client matching” does not complete unless the service-side has discovered both client entities (DataReader and DataWriter). While “client matching” is still in progress, service-side does not process requests from the client.”

Repo: crates/rpc/src/discovery_ext.rs::client_matching_complete; crates/rpc/src/replier.rs::Replier::take_enhanced_requests; crates/zerodds-c-api/src/rpc_discovery_ffi.rs (zerodds_rpc_client_matching_complete); C++: runtime/cpp/include/dds/rpc.hpp

Tests: crates/rpc/src/discovery_ext.rs::tests::the_service_unmasks_a_client_once_both_its_endpoints_are_discovered, crates/rpc/src/discovery_ext.rs::tests::an_unannounced_client_is_unmasked_only_when_accepted, crates/rpc/src/replier.rs::tests::an_enhanced_request_of_an_undiscovered_client_is_held, crates/zerodds-c-api/tests/rpc_discovery.rs::the_extension_is_announced_read_and_decides_the_matching

Status: done — Rust (e305669e2c42) and C++ (17a3aef74360): “client matching” is complete when the reply writer has discovered the reply reader that the client’s request writer names in related_datareader_key, and that reader names the request writer (Figure 7.3). Until then the service processes no request of the client. A client without an announcement is released only with accept_unannounced. crates/java-omgdds writes and reads PIDs 0x0080 to 0x0082 (rtps/RpcDiscovery.java, DiscoveryData.buildEndpoint and parseEndpoint, bound string<256>: an announcement beyond it is refused as in the decoder of crates/rtps; f65fb3965b5e). ZeroDdsParticipant announces service_instance_name on the endpoints of the service and related_*_key on both sides (9993349aff89). Tests: crates/java-omgdds/java/src/test/java/org/zerodds/rtps/RpcDiscoveryTest.java (theThreeParametersTravelWithTheEndpoint, aStringBeyondTheBoundIsRefused, aTopicCorrespondsByNameOrByAlias). The Java runtime applies the matching rule from the announced endpoints (1fddccd2b87b): ReplierImpl holds back the requests of a client whose reply reader the reply writer does not know (Figure 7.3, per client); RequesterImpl sends when the instance’s request reader names a reply writer that the reply reader has discovered (Figure 7.4). An endpoint without an announcement and a binding without discovery data keep the match by topic. Test: crates/rpc/tests/java/RpcRuntimeRoundtrip.java::overTheJavaPsm through crates/rpc/tests/java_rpc_runtime.rs::the_java_rpc_runtime_and_the_generated_services_run_together (needs a JDK; not run on the Mac or on the Linux test host).

§7.6.2.2.1 Client matching: local_mask and release of the client writer

Spec: §7.6.2.2.1, p. 54 and Figure 7.3 — “At the beginning, the service-side DataReader is enabled with local_mask=All_DW so that it does not process any incoming requests. When the service-side DataWriter completes the discovery of a client DataReader, the service DataReader is ready to accept requests from that specific client. Therefore, it unmasks the related client DataWriter.”

Repo: crates/rpc/src/replier.rs::Replier::take_enhanced_requests (hold list per request writer of the client, GUID from the identity of the request); C++: runtime/cpp/include/dds/rpc.hpp (DataReader::client_matching_complete per client)

Tests: crates/rpc/src/replier.rs::tests::an_enhanced_request_of_an_undiscovered_client_is_held, crates/rpc/src/replier.rs::tests::the_named_alternatives_release_a_request_of_an_undiscovered_client, crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together, crates/java-omgdds/java/src/test/java/org/omg/dds/rpc/ReplierClientMatchingTest.java, crates/rpc-rust-e2e/tests/replier_activate_client_matching.rs::an_activated_replier_answers_a_held_request_once_its_client_is_matched

Status: done — Rust (e305669e2c42) and C++ (4b6b049312ff, 17a3aef74360) mask per client: a request is processed only once client_matching_complete holds for that client’s request writer; other clients are not held up by it. Rust sets no local_mask on the DataReader of the DDS layer; the replier takes the samples and holds them in a list of its own. crates/java-omgdds writes and reads PIDs 0x0080 to 0x0082 (rtps/RpcDiscovery.java, DiscoveryData.buildEndpoint and parseEndpoint, bound string<256>: an announcement beyond it is refused as in the decoder of crates/rtps; f65fb3965b5e). ZeroDdsParticipant announces service_instance_name on the endpoints of the service and related_*_key on both sides (9993349aff89). Tests: crates/java-omgdds/java/src/test/java/org/zerodds/rtps/RpcDiscoveryTest.java (theThreeParametersTravelWithTheEndpoint, aStringBeyondTheBoundIsRefused, aTopicCorrespondsByNameOrByAlias). The Java runtime applies the matching rule from the announced endpoints (1fddccd2b87b): ReplierImpl holds back the requests of a client whose reply reader the reply writer does not know (Figure 7.3, per client); RequesterImpl sends when the instance’s request reader names a reply writer that the reply reader has discovered (Figure 7.4). An endpoint without an announcement and a binding without discovery data keep the match by topic. Test: crates/rpc/tests/java/RpcRuntimeRoundtrip.java::overTheJavaPsm through crates/rpc/tests/java_rpc_runtime.rs::the_java_rpc_runtime_and_the_generated_services_run_together (needs a JDK; green on the Linux test host, 3 tests, d67a980f80b). The release hung on a new sample: a replier whose listener runs on arrival (§7.9.2.2 way 1) kept a held request when its client became complete by discovery afterwards and no further sample came (measured with crates/rpc-rust-e2e/tests/java_peer.rs, a Rust client of Base2 against the Java service of Derived2 under load: “held … replyMatched=0”, then the match of the reply writer and no reply). Since 8ae48aed9a0 such a replier checks every 5 ms while requests are held whether one of their clients is complete, and releases then; a polled replier (receiveRequests, waitForRequests, Server) checks at every poll. Test: ReplierClientMatchingTest.java (red on 3f90296146e). The same gap was in Rust Replier::activate (and activate_async), which listened on DATA_AVAILABLE only; since 30bcfe5cc2f a thread of the replier looks at the held requests every 5 ms while some are held. Test: replier_activate_client_matching.rs (the client’s reply reader enters the partition of the reply writer only after the request; without the fix held 1, answered 0).

§7.6.2.2.2 Service matching at the client: no requests until complete

Spec: §7.6.2.2.2, p. 55 — ““service matching” does not complete unless the client-side has discovered both service DDS Entities (DataReader and DataWriter) and it does not send requests to the service until “service matching” completes.”

Repo: crates/rpc/src/discovery_ext.rs::service_matching_complete; crates/rpc/src/requester.rs::Requester::service_matched; crates/zerodds-c-api/src/rpc_discovery_ffi.rs (zerodds_rpc_service_matching_complete); C++: runtime/cpp/include/dds/rpc.hpp

Tests: crates/rpc/src/discovery_ext.rs::tests::the_client_waits_for_both_service_endpoints, crates/rpc/src/discovery_ext.rs::tests::the_two_endpoints_must_name_each_other, crates/rpc/src/discovery_ext.rs::tests::the_client_addresses_the_instance_it_names, crates/rpc/src/discovery_ext.rs::tests::an_unannounced_service_completes_only_when_accepted, crates/rpc-rust-e2e/tests/enhanced_e2e.rs::the_client_waits_for_the_service_instance_it_names, crates/zerodds-c-api/tests/rpc_discovery.rs::the_extension_is_announced_read_and_decides_the_matching

Status: done — Rust (e305669e2c42) and C++ (17a3aef74360): “service matching” is complete when the service’s request reader and reply writer are discovered, name each other, and the request reader announces the client’s instance_name (Figure 7.4); the client does not send before. A service without an announcement is read as complete only with accept_unannounced. crates/java-omgdds writes and reads PIDs 0x0080 to 0x0082 (rtps/RpcDiscovery.java, DiscoveryData.buildEndpoint and parseEndpoint, bound string<256>: an announcement beyond it is refused as in the decoder of crates/rtps; f65fb3965b5e). ZeroDdsParticipant announces service_instance_name on the endpoints of the service and related_*_key on both sides (9993349aff89). Tests: crates/java-omgdds/java/src/test/java/org/zerodds/rtps/RpcDiscoveryTest.java (theThreeParametersTravelWithTheEndpoint, aStringBeyondTheBoundIsRefused, aTopicCorrespondsByNameOrByAlias). The Java runtime applies the matching rule from the announced endpoints (1fddccd2b87b): ReplierImpl holds back the requests of a client whose reply reader the reply writer does not know (Figure 7.3, per client); RequesterImpl sends when the instance’s request reader names a reply writer that the reply reader has discovered (Figure 7.4). An endpoint without an announcement and a binding without discovery data keep the match by topic. Test: crates/rpc/tests/java/RpcRuntimeRoundtrip.java::overTheJavaPsm through crates/rpc/tests/java_rpc_runtime.rs::the_java_rpc_runtime_and_the_generated_services_run_together (needs a JDK; not run on the Mac or on the Linux test host).

§7.6.2.2.2 Service matching: local_mask, queue, release

Spec: §7.6.2.2.2, p. 55 and Figure 7.4 — “At the beginning, the client-side DataWriter is enabled local_mask=All_DR such that it does not send any request at all. Attempts to send requests would be queued. When the client-side DataReader completes the discovery of a service DataWriter, the client DataWriter updates the local mask so that it can send requests to the service DataReader as long as it has been discovered.”

Repo: crates/rpc/src/requester.rs::Requester::wait_for_service (Rust: the sending call holds the request); C++: runtime/cpp/include/dds/rpc.hpp (Requester::queued_requests); Java: runtime/java/src/main/java/org/zerodds/ddsrpc/RequesterImpl.java (queue queue, flushQueue)

Tests: crates/rpc/src/requester.rs::tests::an_enhanced_request_waits_for_the_service_and_fails_without_sending, crates/rpc/src/requester.rs::tests::the_fail_setting_does_not_wait, crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together, crates/rpc/tests/java_rpc_runtime.rs::the_java_rpc_runtime_and_the_generated_services_run_together

Status: done — Rust (e305669e2c42): the client does not send; the call holds the request for at most request_timeout and then fails with RpcError::ServiceNotMatched; the request is not in a queue afterwards. C++ (4b6b049312ff, 17a3aef74360) puts requests in a queue and releases them as soon as service_matching_complete holds; no runtime has a mask local_mask = All_DR, the release takes its place. crates/java-omgdds writes and reads PIDs 0x0080 to 0x0082 (rtps/RpcDiscovery.java, DiscoveryData.buildEndpoint and parseEndpoint, bound string<256>: an announcement beyond it is refused as in the decoder of crates/rtps; f65fb3965b5e). ZeroDdsParticipant announces service_instance_name on the endpoints of the service and related_*_key on both sides (9993349aff89). Tests: crates/java-omgdds/java/src/test/java/org/zerodds/rtps/RpcDiscoveryTest.java (theThreeParametersTravelWithTheEndpoint, aStringBeyondTheBoundIsRefused, aTopicCorrespondsByNameOrByAlias). The Java runtime applies the matching rule from the announced endpoints (1fddccd2b87b): ReplierImpl holds back the requests of a client whose reply reader the reply writer does not know (Figure 7.3, per client); RequesterImpl sends when the instance’s request reader names a reply writer that the reply reader has discovered (Figure 7.4). An endpoint without an announcement and a binding without discovery data keep the match by topic. Test: crates/rpc/tests/java/RpcRuntimeRoundtrip.java::overTheJavaPsm through crates/rpc/tests/java_rpc_runtime.rs::the_java_rpc_runtime_and_the_generated_services_run_together (needs a JDK; not run on the Mac or on the Linux test host).

§7.7 Interface Evolution

§7.7.1 Evolution in the Basic mapping

Spec: §7.7.1, p. 56 — “The Basic Service Profile has limited support for interface evolution […] Interface evolution is constrained by the rules described herein.”

Repo: —

Tests: —

Status: n/a (informative) — introduction.

§7.7.1.1 Client with fewer operations

Spec: §7.7.1.1, p. 56 — “If a client uses an interface that has fewer methods than that of the service, it is simply oblivious of the fact that the service has more capabilities than the client can use.”

Repo: crates/rpc/src/codegen.rs::build_call_union (labels from the name of the operation, not from the position); crates/rpc/src/function_call.rs (dispatch_request by opcode)

Tests: crates/rpc/src/codegen.rs::tests::the_case_labels_are_the_operation_hashes, crates/rpc/tests/profile_conformance.rs::function_call_processing_dispatches_to_correct_operation, crates/rpc-rust-e2e/tests/evolution_styles_discovery.rs::versions::an_old_client_calls_a_new_service

Status: done — the label of an operation is the HASH of its name (64d55a6c8f94, c4a68d078000) and does not depend on the other operations of the interface; the service calls by label. For Enhanced a client of the old version runs against the service of the new version (test 3, 414e077c527d); for Basic there are three generated versions (basic_old, basic_new, basic_fewer in crates/rpc-rust-e2e/build.rs, b21c700bc86e) and the tests evolution_styles_discovery.rs::basic_versions::a_client_with_fewer_operations_calls_a_service_with_more, an_old_basic_client_calls_a_new_service and a_new_basic_client_calls_an_old_service.

§7.7.1.1 Client with more operations: REMOTE_EX_UNSUPPORTED

Spec: §7.7.1.1, p. 56 — “If the client uses an interface with more operations than that of the service, invocation of an unsupported operation shall result in REMOTE_EX_UNSUPPORTED remote exception code.”

Repo: crates/lang-rules/src/emit/interface_rust.rs (dispatcher, case unknown operation: RemoteExceptionCode::Unsupported); crates/lang-rules/src/emit/interface_java/calls.rs; crates/lang-rules/src/emit/interface_cpp/calls.rs (method answer, case default)

Tests: crates/rpc-rust-e2e/tests/e2e.rs::the_generated_calculator_binding_runs_every_call (expects Unsupported), crates/rpc/tests/java_rpc_runtime.rs::the_generated_function_call_client_calls_the_generated_service (FunctionCallRoundtrip.java, expects RemoteUnsupportedError), crates/rpc/tests/cpp_function_call.rs::the_generated_client_calls_the_generated_service (function_call_roundtrip.cpp, expects RemoteUnsupportedError)

Status: done — the generated Rust dispatcher (b527a9f58028), the generated Java service (c512ee365514) and the generated C++ service of the Basic mapping (62ccb5f757a3) answer an unknown operation with REMOTE_EX_UNSUPPORTED; the C++ client throws RemoteUnsupportedError. The spec has two statements here (§7.7.1.1: REMOTE_EX_UNSUPPORTED; table in §7.5.2: REMOTE_EX_UNKNOWN_OPERATION for “The operation called is unknown”); the mapping follows §7.7.1.1. The Enhanced dispatcher answers REMOTE_EX_UNKNOWN_OPERATION (§7.7.2.1; enhanced_function_call_roundtrip.cpp).

§7.7.1.2 Order of operations and bases without effect

Spec: §7.7.1.2, p. 56 — “Reordering operations has no impact on the semantics of the interface because every interface has set semantics. […] Reordering base interfaces has no impact on the semantics of the interface.”

Repo: crates/rpc/src/codegen.rs::build_call_union (labels from the name, not from the position); crates/rpc/src/evolution_rules.rs::is_compatible

Tests: crates/rpc/src/codegen.rs::tests::the_case_labels_are_the_operation_hashes, crates/rpc/src/evolution_rules.rs::tests::basic_mapping_reorder_operations_is_compatible

Status: done — the label of an operation is the HASH of its name (64d55a6c8f94); the order of operations and bases changes no label. The table evolution_rules names reordering compatible in Basic (17fe2de3f32e).

§7.7.1.3 No change of the signature in the Basic mapping

Spec: §7.7.1.3, p. 56 — “The Basic Service Profile shall not support any modifications to the operation signatures including exception specification.”

Repo: crates/rpc/src/evolution_rules.rs::is_compatible (Basic: ChangeSignature and the Enhanced changes incompatible)

Tests: crates/rpc/src/evolution_rules.rs::tests::basic_mapping_change_signature_is_breaking

Status: done — in the Basic mapping no change of a signature is treated as compatible (17fe2de3f32e); the Basic types are @final and carry no member IDs.

§7.7.2 Evolution in the Enhanced mapping

Spec: §7.7.2, p. 56 — “The Enhanced Service Profile supports flexible interface evolution. […] The interface mapping rules in the previous sub clause are designed such that the assignability rules defined in [DDS-XTypes] will ensure seamless evolution from Iold to Inew.”

Repo: —

Tests: —

Status: n/a (informative) — introduction and terms; the rules follow as items.

§7.7.2.1 New operation

Spec: §7.7.2.1, pp. 56–57 — “Cold can invoke Snew because the additional member in Requestnew is never populated by Cold. […] When Cnew invokes Sold, Sold receives a sample with no active member […] In such cases, the service (Sold) returns Replyold with remoteEx = REMOTE_EX_UNKNOWN_OPERATION.”

Repo: crates/lang-rules/src/emit/interface_rust/enhanced.rs (choice_codec: an unknown member ID becomes UnknownOp; answer_unknown_operations); C++: crates/lang-rules/src/emit/interface_cpp/enhanced_codec.rs, crates/lang-rules/src/emit/interface_cpp/calls.rs; Java: crates/lang-rules/src/emit/interface_java/enhanced_calls.rs

Tests: crates/rpc-rust-e2e/tests/enhanced_generated.rs::a_member_the_interface_does_not_have_is_unknown_operation, crates/rpc-rust-e2e/tests/enhanced_generated.rs::an_unknown_member_is_answered_unknown_operation, crates/rpc-rust-e2e/tests/enhanced_generated.rs::a_reply_carries_remote_ex, crates/rpc/tests/cpp_enhanced_function_call.rs::the_generated_enhanced_client_calls_the_generated_enhanced_service, crates/rpc/tests/java_enhanced_codec.rs::the_generated_java_codec_writes_the_octets_of_the_clause

Status: done — the member IDs are the HASH of the name; a member the service’s version does not know leaves the request choice without an active member (Rust UnknownOp) and the service answers remoteEx = REMOTE_EX_UNKNOWN_OPERATION (Rust 41b3b02f7a20, C++ 45ead22cc2b9, Java 2ea77f7dad8a). An old client reaches a new service because it never sets the additional member. Rust and C++ run the case; for Java the tests check the codec and the generated text (enhanced_java_calls.rs).

§7.7.2.2 Removed operation

Spec: §7.7.2.2, p. 57 — “When Cold calls Snew, Cold receives REMOTE_EX_UNKNOWN_OPERATION RemoteExceptionCode.”

Repo: as for “§7.7.2.1 New operation”; the client reads remoteEx as RpcError::RemoteException (crates/rpc/src/enhanced.rs)

Tests: crates/rpc-rust-e2e/tests/enhanced_generated.rs::an_unknown_member_is_answered_unknown_operation, crates/rpc-rust-e2e/tests/enhanced_e2e.rs::an_enhanced_remote_exception_is_the_remote_ex_member, crates/rpc/src/enhanced.rs::tests::a_remote_ex_reply_round_trips_every_code

Status: done — when a client calls an operation the new service no longer has, it receives REMOTE_EX_UNKNOWN_OPERATION (41b3b02f7a20, e305669e2c42). A new client with a subset of the old service’s operations is the case of “fewer operations” in §7.7.1.1, here without an error.

§7.7.2.3 Order of operations and bases

Spec: §7.7.2.3, p. 57 — “Due to the use of md5 hash algorithm to compute the member ids, this specification considers two interfaces equivalent as long as they contain the same operations.”

Repo: crates/rpc/src/codegen.rs::build_enhanced_service (@Autoid: member ID = HASH of the name, 28 bits); crates/rpc/src/evolution_rules.rs::is_compatible

Tests: crates/rpc/src/codegen.rs::tests::enhanced_autoid_member_ids_are_the_hash_of_the_name, crates/rpc/src/codegen.rs::tests::enhanced_inheritance_is_flattened, crates/rpc/src/evolution_rules.rs::tests::enhanced_mapping_reorder_operations_is_compatible

Status: done — the member ID of an operation is the HASH of its name, not its position (0edbbcf11324); two interfaces with the same operations have the same IDs whatever the order of operations and bases.

§7.7.2.4 Duck Typing

Spec: §7.7.2.4, p. 57 — “Enhanced Service Profile supports “duck typing” evolution of an interface.”

Repo: crates/rpc/src/codegen.rs::build_enhanced_service (flat inheritance, type names of the base); crates/lang-rules/src/emit/interface_rust/enhanced.rs (derived dispatcher serves inherited operations)

Tests: crates/rpc/src/codegen.rs::tests::enhanced_inheritance_is_flattened, crates/rpc-rust-e2e/tests/enhanced_generated.rs::a_derived_request_has_the_inherited_operation, crates/rpc-rust-e2e/tests/enhanced_generated.rs::a_derived_dispatcher_serves_an_inherited_member

Status: done — the request choice of a derived interface contains the inherited operations with the same member IDs they would have in the interface itself (0edbbcf11324, 7607e8680852); the topic names come from the name of the interface. An interface with inherited operations and one with directly defined operations of the same name are the same on the wire.

§7.7.2.5.1 Adding or removing parameters

Spec: §7.7.2.5.1, p. 57 — “Adding and removing parameters in an operation shall break compatibility with the older interface. The @final annotation on the In and Out structures enforce this restriction. It is, however, possible to mark an operation @mutable to allow the In and Out structures to be mutable”.

Repo: crates/rpc/src/codegen.rs::build_enhanced_service (In, Out, Result are @final, with @Mutable on the operation @mutable); crates/lang-rules/src/emit/interface_rust/enhanced.rs; the codecs for C++ and Java

Tests: crates/rpc-rust-e2e/tests/enhanced_generated.rs::a_mutable_operation_has_mutable_structures, crates/rpc-rust-e2e/tests/enhanced_generated.rs::a_mutable_structure_skips_a_member_it_does_not_know, crates/rpc-rust-e2e/tests/enhanced_generated.rs::an_absent_member_of_a_mutable_structure_takes_its_default, crates/rpc/src/codegen.rs::tests::enhanced_mutable_operation_has_mutable_structures, crates/rpc/src/evolution_rules.rs::tests::enhanced_mapping_add_remove_param_is_breaking; C++: crates/rpc/tests/cpp_enhanced_function_call.rs::the_generated_enhanced_client_calls_the_generated_enhanced_service; Java: crates/rpc/tests/java_enhanced_codec.rs::the_generated_java_codec_writes_the_octets_of_the_clause

Status: done — without @Mutable the structures are @final and carry no member headers (an extra parameter breaks compatibility); with @Mutable each parameter carries an EMHEADER with the ID of the name, an unknown member is skipped and a missing one takes its default (41b3b02f7a20, 77ded59f712c). The table evolution_rules names adding and removing parameters incompatible (17fe2de3f32e).

§7.7.2.5.2 Reordering parameters

Spec: §7.7.2.5.2, p. 57 — “Reordering parameters in an operation shall break compatibility with the older interface. […] It is, however, possible to mark an operation @mutable to allow reordering of parameters. In that case the synthesized structures (In and Out) shall be annotated @mutable.”

Repo: crates/rpc/src/codegen.rs::build_enhanced_service (member IDs from the parameter name; @final without @Mutable)

Tests: crates/rpc-rust-e2e/tests/enhanced_generated.rs::a_mutable_operation_has_mutable_structures, crates/rpc/src/evolution_rules.rs::tests::enhanced_mapping_reorder_params_is_breaking, crates/rpc-rust-e2e/tests/evolution_styles_discovery.rs::versions::an_old_client_calls_a_new_service, crates/rpc-rust-e2e/tests/evolution_styles_discovery.rs::versions::a_new_client_calls_an_old_service

Status: done — without @Mutable the parameters stand without headers in the order of the declaration (test 1, case Calc_add_In), reordering breaks compatibility; with @Mutable every parameter has an ID from its name (41b3b02f7a20). Two generated versions of interface Svc have @Mutable void mix(in long x, in long y) and @Mutable void mix(in long y, in long x); client and service of the other version exchange the arguments under their names. Rust: tests 3 and 4 (414e077c527d). C++: crates/rpc/tests/cpp/enhanced_evolution_roundtrip.cpp through crates/rpc/tests/cpp_enhanced_function_call.rs::two_generated_cpp_versions_of_an_interface_run_against_each_other (49525d7e5e80, run on the Linux test host). Java: crates/rpc/tests/java/EvolutionChecks.java through crates/rpc/tests/java_enhanced_codec.rs::two_generated_java_versions_of_an_interface_run_against_each_other (19add727524b, needs a JDK).

§7.7.2.5.3 Changing the type of a parameter

Spec: §7.7.2.5.3, p. 57 — “Changing the type of the parameters is allowed by this specification. The type assignability rules shall be as described in [DDS-XTypes].”

Repo: —

Tests: crates/rpc-rust-e2e/tests/java_peer.rs::a_java_client_calls_a_rust_service, crates/rpc-rust-e2e/tests/java_peer.rs::a_rust_client_calls_a_java_service, crates/rpc-rust-e2e/tests/java_peer.rs::versions::a_changed_parameter_type_does_not_match_the_java_client, crates/rpc-rust-e2e/tests/java_peer.rs::versions::an_old_java_client_calls_an_old_rust_service, crates/rpc-rust-e2e/tests/java_peer.rs::appended_member::a_member_appended_to_a_mutable_structure_matches_the_java_client

Status: done — Rust and C++ are implemented: the topics carry the TypeInformation, the pairing follows assignability under XTypes. Tests (Linux test host, green): crates/rpc-rust-e2e/tests/enhanced_type_information.rs::appended_member::a_member_appended_to_a_parameter_type_is_matched (a member appended to a @mutable structure), ...::versions::a_changed_parameter_type_does_not_match (long to string: ServiceNotMatched; with a match by type name the request would be sent and refused by the service, measured with a control run); for C++ cpp_rpc_real_library.rs::the_cpp_binding_runs_against_libzerodds (ev_changed: the client does not find the service). Java (2d0f809c6e2, 9b1608508c5, d67a980f80b), against Rust peers over RTPS: crates/rpc-rust-e2e/tests/java_peer.rs::versions::a_changed_parameter_type_does_not_match_the_java_client (long to string: the Java client finds no service, the Rust service sees no request; on 78f243b596f, before the matching by assignability, the Java client matched by type name, called the service and got no reply), control ...::versions::an_old_java_client_calls_an_old_rust_service, and ...::appended_member::a_member_appended_to_a_mutable_structure_matches_the_java_client (a member appended to Pose: match, the argument reaches the service). The table evolution_rules calls the change compatible (enhanced_mapping_change_param_type_is_compatible).

§7.7.2.5.4 Adding or removing the return type

Spec: §7.7.2.5.4, p. 57 — “Adding and removing return type shall break compatibility with the older interface. […] It is, however, possible to annotate an operation @Mutable to allow the In and Out structures to be mutable and consequently support addition or removal of return type”.

Repo: crates/rpc/src/codegen.rs::build_enhanced_service (the return value is the member return of the Out structure; @final, with @Mutable @mutable)

Tests: crates/rpc/src/codegen.rs::tests::enhanced_out_carries_the_return_value, crates/rpc/src/codegen.rs::tests::enhanced_mutable_operation_has_mutable_structures, crates/rpc-rust-e2e/tests/enhanced_generated.rs::an_absent_member_of_a_mutable_structure_takes_its_default, crates/rpc/src/evolution_rules.rs::tests::enhanced_mapping_add_remove_return_type_is_breaking

Status: done — the return value is a member of the Out structure; without @Mutable it is @final (adding or removing breaks compatibility), with @Mutable it is @mutable and read like the In structure (41b3b02f7a20, 77ded59f712c). The tests for decoding a missing and an unknown member run on the In structure; the codec of the Out structure is produced by the same generator.

§7.7.2.5.5 Changing the return type

Spec: §7.7.2.5.5, p. 58 — “Changing the type of the return value is allowed by this specification. The type assignability rules shall be as described in [DDS-Xtypes].”

Repo: —

Tests: crates/rpc/tests/cpp_rpc_real_library.rs::the_cpp_binding_runs_against_libzerodds, crates/rpc-rust-e2e/tests/java_peer.rs::a_java_client_calls_a_rust_service, crates/rpc-rust-e2e/tests/java_peer.rs::a_rust_client_calls_a_java_service, crates/rpc-rust-e2e/tests/java_peer.rs::versions::a_return_type_the_old_one_is_not_assignable_to_does_not_match_the_java_client, crates/rpc-rust-e2e/tests/java_peer.rs::appended_member::a_member_appended_to_a_mutable_structure_matches_the_java_client

Status: done — Rust is implemented as for “§7.7.2.5.3 Changing the type of a parameter”. Tests (Linux test host, green): crates/rpc-rust-e2e/tests/enhanced_type_information.rs::return_type::a_return_type_the_old_one_is_not_assignable_to_does_not_match (long to long long: ServiceNotMatched) and ...::appended_member::a_return_type_with_an_appended_member_is_matched (a member appended to a @mutable structure in the return type: the old client reads the reply of the new service, f447919ebed2). C++ carries the same TypeInformation (item on §7.5.1.2.6); cpp_rpc_real_library.rs::the_cpp_binding_runs_against_libzerodds checks a return type with an appended member (the old client reads the reply) and one widened from long to long long (no match) (a7f9353650e). Java (2d0f809c6e2, d67a980f80b), against Rust peers over RTPS: crates/rpc-rust-e2e/tests/java_peer.rs::versions::a_return_type_the_old_one_is_not_assignable_to_does_not_match_the_java_client (long to long long: the reply reader of the Java client does not match the writer of the service; on 78f243b596f it matched by type name and the call of add went through) and ...::appended_member::a_member_appended_to_a_mutable_structure_matches_the_java_client (return type Pose with an appended member: the Java client reads origin.x=3). The table evolution_rules calls the change compatible (enhanced_mapping_change_return_type_is_compatible).

§7.7.2.5.6 Adding or removing an exception

Spec: §7.7.2.5.6, p. 58 — “This specification supports adding and removing one or more exceptions on an operation. The @mutable annotation on the return structure will support this interface evolution.”

Repo: crates/rpc/src/codegen.rs::build_enhanced_service (Result is a choice over result and <name>_ex, member IDs from the name); crates/lang-rules/src/emit/interface_rust/enhanced.rs (choice_codec of the Result without UnknownOp); C++: crates/lang-rules/src/emit/interface_cpp/calls.rs; Java: crates/lang-rules/src/emit/interface_java/enhanced_calls.rs

Tests: crates/rpc/src/codegen.rs::tests::enhanced_result_carries_out_and_the_exceptions, crates/rpc-rust-e2e/tests/enhanced_generated.rs::a_result_is_a_choice_of_the_result_and_the_exceptions, crates/rpc/src/evolution_rules.rs::tests::enhanced_mapping_add_remove_exception_is_compatible, crates/rpc-rust-e2e/tests/enhanced_generated.rs::an_unknown_exception_member_of_a_result_decodes_as_unknown_ex, crates/rpc-rust-e2e/tests/enhanced_generated.rs::the_generated_client_reports_unknown_exception_for_an_unknown_result_member, crates/rpc-rust-e2e/tests/enhanced_generated.rs::an_exception_the_operation_does_not_declare_is_unknown_exception, crates/rpc/tests/java_enhanced_codec.rs::the_generated_java_service_and_client_answer_the_error_cases_of_the_clauses

Status: done — every exception is a member <name>_ex of the Result choice with an ID from the name (41b3b02f7a20); adding or removing an exception does not change the IDs of the others. The generated Rust client reports an unknown _ex member of the Result as RpcError::RemoteException with REMOTE_EX_UNKNOWN_EXCEPTION, and so an undeclared exception of the service (f88947810821). Java: EnhancedRuntimeChecks.java (82ec363b6b82) and EvolutionChecks.java (19add727524b). C++: enhanced_function_call_roundtrip.cpp checks an undeclared exception of the implementation and a Result with an unknown member (the client throws RemoteUnknownExceptionError), enhanced_evolution_roundtrip.cpp the version with an added exception against the one without (49525d7e5e80, run on the Linux test host).

§7.7.2.5.6 REMOTE_EX_UNKNOWN_EXCEPTION for an unknown exception

Spec: §7.7.2.5.6, p. 58 — “The language binding that provides function call/return semantics may throw REMOTE_EX_UNKNOWN_EXCEPTION if the RPC call results into an exception that client does not understand.”

Repo: —

Tests: —

Status: n/a (informative) — permission.

§7.7 — table of evolution

Spec: §7.7.1.1 to §7.7.2.5.6, pp. 56–58 — as the items above.

Repo: crates/rpc/src/evolution_rules.rs::is_compatible and compatible_evolutions

Tests: crates/rpc/src/evolution_rules.rs::tests::basic_mapping_add_remove_operation_is_compatible, crates/rpc/src/evolution_rules.rs::tests::basic_mapping_has_four_compatible_evolutions, crates/rpc/src/evolution_rules.rs::tests::enhanced_compatible_evolutions_includes_8_of_12, crates/rpc/src/evolution_rules.rs::tests::a_mutable_operation_allows_parameter_changes, crates/rpc/src/evolution_rules.rs::tests::mutable_changes_nothing_that_was_compatible_or_never_was, crates/rpc/src/evolution_rules.rs::tests::a_mutable_operation_has_eleven_compatible_enhanced_evolutions

Status: done — the table agrees with §7.7.1.1 to §7.7.2.5.6 (17fe2de3f32e): Basic names adding, removing and reordering operations compatible and every change of the signature incompatible; Enhanced names type changes and adding or removing exceptions compatible and adding, removing and reordering parameters and return type incompatible. With mutable = true in is_compatible and compatible_evolutions it names the three changes compatible that the spec allows with @mutable (§7.7.2.5.1, .2, .4; 943d3afd7cb6). No code outside the tests calls the table; the spec asks for no run-time check (read from the code).


§7.8 Request and Reply Correlation

§7.8.1 Basic: correlation through RequestHeader and ReplyHeader

Spec: §7.8.1, p. 58 — “The Basic service profile uses the RequestHeader and ReplyHeader described in sub clause 7.5.1.1.1.”

Repo: crates/rpc/src/requester.rs::Requester::tick (related_request_id against the outstanding requests); crates/rpc/src/replier.rs::Replier::tick

Tests: crates/rpc/src/requester.rs::tests::tick_correlates_reply_with_pending_slot, crates/rpc/tests/runtime_e2e.rs::e2e_multi_pending_requests_all_get_their_reply, crates/rpc/tests/runtime_e2e.rs::e2e_client_side_request_identity_is_the_one_the_reply_relates_to, crates/rpc-rust-e2e/tests/e2e.rs::a_live_request_identity_is_the_rtps_identity_of_the_request_writer

Status: done — the Rust runtime correlates through RequestHeader::request_id and ReplyHeader::related_request_id (f06c1eaf3d3a); the request_id is the GUID and sequence number of the request writer (2314c1c5fb58). For C++ and Java see the next item.

§7.8.1 C++ and Java: requestId in the header, correlation through relatedRequestId

Spec: §7.8.1, p. 58 — as above.

Repo: C++: runtime/cpp/include/dds/rpc.hpp (Requester::send_request enters the identity from DataWriter::next_identity() into RequestHeader::request_id, Replier::dispatch_requests replies with header.request_id); Java: runtime/java/src/main/java/org/zerodds/ddsrpc/RequesterImpl.java, ReplierImpl.java

Tests: crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together (the in-memory binding hands out no identity), crates/rpc/tests/java_rpc_runtime.rs::the_java_rpc_runtime_and_the_generated_services_run_together

Status: done — the header carries the explicit request_id, the replier reads it from the header, not from SampleInfo (58634aa2702a); requesters filter foreign replies by the GUID of their request writer (35aa702e4900). The bindings to ZeroDDS in C++ and Java also hand out the identity of the sample (2bfb2786121b, a2a9a67acb58).

Spec: §7.8.2, p. 58 — “To support propagation of the sample identity of a related request this specification extends the [RTPS] specification adding a new parameter id PID_RELATED_SAMPLE_IDENTITY with value 0x0083. This parameter may appear in the inlineQos sub-message element of the DATA sub-message”.

Repo: crates/rtps/src/parameter_list.rs (pid::RELATED_SAMPLE_IDENTITY); crates/rtps/src/inline_qos.rs (related_sample_identity_param, find_related_sample_identity)

Tests: crates/rtps/src/inline_qos.rs::tests::related_sample_identity_param_uses_pid_0x0083, crates/rtps/src/inline_qos.rs::tests::find_related_sample_identity_finds_pid, crates/rtps/src/parameter_list.rs::tests::rpc_pid_constants_match_spec

Status: done — parameter ID 0x0083, encoding and lookup in the inline QoS (b5224bd70dbb); reading masks only the must-understand bit, a vendor-specific ID 0x8083 is not read as 0x0083 (1a30e3dd368a).

Spec: §7.8.2, p. 58 — “The PID_RELATED_SAMPLE_IDENTITY shall be used for data samples sent as reply to a request.”

Repo: crates/dcps/src/publisher.rs::DataWriter::write_related and crates/dcps/src/runtime.rs::DcpsRuntime::write_user_sample_related (write 0x0083 and eProsima’s 0x800f); crates/rpc/src/replier.rs (Enhanced reply through write_related); C++: zerodds_writer_write_related in crates/zerodds-c-api; Java: runtime/java/src/main/java/org/zerodds/ddsrpc/ZeroDdsParticipant.java (Writer.write(sample, related)); crates/rmw-zerodds-shim/src/services.rs

Tests: crates/rtps/src/inline_qos.rs::tests::reply_inline_qos_contains_only_pid_0x0083, crates/dcps/src/runtime.rs::tests::the_related_identity_is_0x0083_or_eprosimas_0x800f_from_a_writer_that_means_it, crates/rpc-rust-e2e/tests/enhanced_e2e.rs::an_enhanced_call_is_answered_through_the_related_sample_identity, crates/rpc/tests/cpp_rpc_zerodds_related_identity.rs::the_zerodds_binding_sends_and_reads_the_related_sample_identity, crates/java-omgdds/java/src/test/java/org/omg/dds/rpc/ZeroDdsParticipantTest.java::aWriteReturnsItsIdentityAndTheReaderSeesItWithTheRelatedOne

Status: done — in the Enhanced mapping every reply carries parameter 0x0083 with the identity of the request and the requester correlates by it: Rust (8385434c2326, e305669e2c42), C++ (2bfb2786121b, 5a472acf053e), Java (a2a9a67acb58, the Java PSM writer returns the identity and takes a related one). The Basic mapping correlates through the header (§7.8.1). The ROS 2 services use the same write path.

Spec: §7.8.2, p. 58 — as above.

Repo: Rust: crates/rpc/src/replier.rs::Replier::write_reply (Enhanced: DataWriter::write_related), crates/rpc/src/requester.rs::Requester::tick (reads the related identity from SampleWire), crates/dcps/src/publisher.rs::DataWriter::write_related, crates/dcps/src/runtime.rs::DcpsRuntime::write_user_sample_related, crates/dcps/src/subscriber.rs::DataReader::take_with_wire, crates/rtps/src/inline_qos.rs::find_related_sample_identity. C++: runtime/cpp/include/dds/rpc/zerodds.hpp (Writer::write_related, Reader::take) through zerodds_writer_write_related and zerodds_reader_take_wire of the C API. Java: runtime/java/src/main/java/org/zerodds/ddsrpc/ZeroDdsParticipant.java (Writer.write(sample, related), Reader.take) through DataWriterImpl.writeIdentified of the Java PSM. Commits: 1a30e3dd368a (rtps: 0x8083 is no longer read as 0x0083), 8385434c2326 (dcps), 5a472acf053e (c-api), e305669e2c42 (Rust), 2bfb2786121b (C++), a2a9a67acb58 (Java)

Tests: crates/rtps/src/inline_qos.rs::tests::a_vendor_specific_0x8083_is_not_the_related_sample_identity, crates/rtps/src/inline_qos.rs::tests::find_related_sample_identity_with_must_understand_bit_works, crates/dcps/src/subscriber.rs::tests::take_with_wire_hands_over_the_identity_and_the_related_identity, crates/dcps/src/publisher.rs::tests::write_related_without_a_runtime_is_refused, crates/zerodds-c-api/tests/related_sample_identity.rs::a_related_sample_identity_reaches_the_reader_with_the_wire_identity, crates/rpc-rust-e2e/tests/enhanced_e2e.rs::an_enhanced_call_is_answered_through_the_related_sample_identity, crates/rpc/tests/cpp_rpc_zerodds_related_identity.rs::the_zerodds_binding_sends_and_reads_the_related_sample_identity, crates/java-omgdds/java/src/test/java/org/omg/dds/rpc/ZeroDdsParticipantTest.java::aWriteReturnsItsIdentityAndTheReaderSeesItWithTheRelatedOne

Status: done — in Rust, C++ and Java the replier of the Enhanced mapping writes the reply with the parameter, and the requester reads it. The Basic mapping carries the identity in the ReplyHeader (§7.8.1). The Rust tests of the Enhanced path run requester and replier on one participant (delivery inside the runtime); the encoding in the inline QoS is checked by the tests in crates/rtps.

§7.8.2 Value is the CDR encoding of SampleIdentity

Spec: §7.8.2, p. 58 — “When present, it shall contain the CDR serialization of the SampleIdentity structure defined below.”

Repo: crates/rtps/src/inline_qos.rs::SampleIdentityBytes (to_bytes, from_bytes)

Tests: crates/rtps/src/inline_qos.rs::tests::sample_identity_layout_is_24_bytes, crates/rtps/src/inline_qos.rs::tests::sample_identity_roundtrip_le, crates/rtps/src/inline_qos.rs::tests::sample_identity_roundtrip_be

Status: done — 24 octets: GUID and sequence number in the byte order of the parameter.

§7.8.2 Value equal to the identity of the request sample

Spec: §7.8.2, p. 58 — “The value of the PID_RELATED_SAMPLE_IDENTITY in a reply message shall be identical to the sample identity (GUID, SN) of the request sample that triggered the reply.”

Repo: Rust: crates/rpc/src/replier.rs::Replier::receive_requests (RequestIdentity::from_inline_qos from the writer GUID and sequence number of the DATA), Replier::send_reply and Replier::write_reply (write_related with that identity). C++: runtime/cpp/include/dds/rpc/core.hpp::Replier::send_reply with Correlation::SAMPLE_IDENTITY (Writer::write_related). Java: runtime/java/src/main/java/org/zerodds/ddsrpc/ReplierImpl.java::sendReply (DataWriter.write(sample, relatedRequestId)). Commits: e305669e2c42 (Rust), 2bfb2786121b (C++), 771f12846807 and a2a9a67acb58 (Java)

Tests: crates/rpc/src/replier.rs::tests::an_enhanced_request_is_identified_by_its_data, crates/rpc/src/requester.rs::tests::an_enhanced_reply_is_correlated_by_its_related_identity, crates/rpc-rust-e2e/tests/enhanced_e2e.rs::an_enhanced_call_is_answered_through_the_related_sample_identity, crates/rpc/tests/runtime_e2e.rs::e2e_client_side_request_identity_is_the_one_the_reply_relates_to, crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together, crates/rpc/tests/java_rpc_runtime.rs::the_java_rpc_runtime_and_the_generated_services_run_together

Status: done — the reply carries the identity of the request sample that the reader of the replier delivered; in Rust a request without an identity on its DATA is counted (Replier::unidentified_requests), not answered.

Spec: §7.8.2, p. 58 — “The RELATED_SAMPLE_IDENTITY_INVALID constant is used to indicate an invalid/non-existing sample identity. […] RELATED_SAMPLE_IDENTITY_INVALID is defined as { GUID_UNKNOWN , SEQUENCENUMBER_UNKNOWN } both of which are defined in the [RTPS] specification.”

Repo: crates/rpc/src/common_types.rs::SampleIdentity::RELATED_SAMPLE_IDENTITY_INVALID (SampleIdentity::UNKNOWN is an alias); runtime/cpp/include/dds/rpc/base.hpp::related_sample_identity_invalid; runtime/java/src/main/java/org/omg/dds/rpc/SampleIdentity.java::RELATED_SAMPLE_IDENTITY_INVALID. Commits: 2fe2b7cdea14, 6c1e75d0c116

Tests: crates/rpc/src/common_types.rs::tests::sample_identity_invalid_constant_is_rtps_unknown, crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together (program rpc_runtime_roundtrip.cpp: “the invalid related identity has SEQUENCENUMBER_UNKNOWN {-1, 0}”), crates/rpc/tests/java_rpc_runtime.rs::the_java_rpc_runtime_and_the_generated_services_run_together (program RpcRuntimeRoundtrip.java: “SEQUENCENUMBER_UNKNOWN.high is -1” and “SEQUENCENUMBER_UNKNOWN.low is 0”)

Status: done — all three runtimes have the constant with SEQUENCENUMBER_UNKNOWN = {high = -1, low = 0}; C++ and Java keep the “unset” value (sequence number 0) apart from it. The C++ program (ea817b7746ef) and the Java program check the value of related_sample_identity_invalid() and RELATED_SAMPLE_IDENTITY_INVALID; the Java program also checks the octets in the ReplyHeader. The programs were read in the code; a run on the Linux test host after these commits is pending.

§7.8.2.1 Retrieve the identity of the request at the service

Spec: §7.8.2.1, p. 58 — “This specification provides language bindings (7.11 Language Bindings) to retrieve the sample identity of the request in the form of a SampleIdentity object.”

Repo: runtime/cpp/include/dds/rpc.hpp (Replier::receive_requests, Sample::identity; filled by Reader::take in runtime/cpp/include/dds/rpc/zerodds.hpp); runtime/java/src/main/java/org/omg/dds/rpc/Sample.java (identity; TakenSample.identity from SampleImpl.identity() of the Java PSM in ZeroDdsParticipant.Reader.take); Rust: crates/rpc/src/replier.rs::PendingRequest::identity. Commits: 2ea2abb7d843 (C++ classes), 2bfb2786121b (C++), 771f12846807 and a2a9a67acb58 (Java), c5af5c7c138e (Rust)

Tests: crates/rpc/tests/cpp_rpc_zerodds_related_identity.rs::the_zerodds_binding_sends_and_reads_the_related_sample_identity, crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together, crates/rpc/tests/java_rpc_runtime.rs::the_java_rpc_runtime_and_the_generated_services_run_together, crates/java-omgdds/java/src/test/java/org/omg/dds/rpc/ZeroDdsParticipantTest.java::aWriteReturnsItsIdentityAndTheReaderSeesItWithTheRelatedOne, crates/rpc/src/replier.rs::tests::receive_requests_and_send_reply_expose_the_identity

Status: done — C++ and Java (the language bindings of the spec) deliver the identity of the request on the Sample; the Rust runtime delivers it on the PendingRequest.

§7.8.2.1 Identity of the request in the Rust runtime

Spec: §7.8.2.1, p. 58 — as above.

Repo: crates/rpc/src/replier.rs (ReplierHandler::handle receives only the value; AsyncReplierHandler::on_request(replier, request, identity) and PendingRequest::identity carry a RequestIdentity); crates/rpc/src/request_identity.rs::RequestIdentity. Commit: c5af5c7c138e

Tests: crates/rpc/src/replier.rs::tests::receive_requests_and_send_reply_expose_the_identity, crates/rpc/src/replier.rs::tests::dispatch_async_hands_the_replier_and_the_identity_to_the_listener

Status: done — the synchronous listener of the Rust runtime (way 1) receives only the value of the request; ways 2 and 3 receive the identity. The spec defines the operation for C++ and Java; Rust is not one of its language bindings. The module documentation of request_identity.rs names a function current_request_identity that does not exist.

Spec: §7.8.2.2, p. 58 — “This specification provides language bindings (7.11 Language Bindings) to retrieve the related sample identity of the reply from the reply SampleInfo in the form of a SampleIdentity object.”

Repo: runtime/cpp/include/dds/rpc.hpp (Sample::related_identity from SampleInfo::related_identity; filled by Reader::take in runtime/cpp/include/dds/rpc/zerodds.hpp from the parameter, in the Basic mapping by Requester::decode_reply from the ReplyHeader); runtime/java/src/main/java/org/omg/dds/rpc/Sample.java (relatedIdentity; TakenSample.relatedIdentity from SampleImpl.relatedIdentity() of the Java PSM). Commits: 2bfb2786121b (C++), 771f12846807 and a2a9a67acb58 (Java)

Tests: crates/rpc/tests/cpp_rpc_zerodds_related_identity.rs::the_zerodds_binding_sends_and_reads_the_related_sample_identity, crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together, crates/rpc/tests/java_rpc_runtime.rs::the_java_rpc_runtime_and_the_generated_services_run_together, crates/java-omgdds/java/src/test/java/org/omg/dds/rpc/ZeroDdsParticipantTest.java::aWriteReturnsItsIdentityAndTheReaderSeesItWithTheRelatedOne

Status: done — C++ and Java deliver the related identity on the reply sample from the information of the sample; in the Enhanced mapping it comes from PID_RELATED_SAMPLE_IDENTITY.

Spec: §7.8.2.2, p. 58 — as above.

Repo: crates/dcps/src/subscriber.rs::DataReader::take_with_wire (SampleWire::related_sample_identity); crates/rpc/src/requester.rs::Requester::tick (assigns replies of the Enhanced mapping through the related identity; Requester::uncorrelated_replies counts replies without it). Commits: 8385434c2326, e305669e2c42

Tests: crates/dcps/src/subscriber.rs::tests::take_with_wire_hands_over_the_identity_and_the_related_identity, crates/rpc/src/requester.rs::tests::an_enhanced_reply_is_correlated_by_its_related_identity, crates/rpc/src/requester.rs::tests::an_enhanced_reply_without_a_related_identity_is_counted

Status: done — SampleInfo of the DCPS layer has no field for it; the runtime reads it from SampleWire. The Rust Requester gives the caller the payload of the reply that it assigned to the request through this identity. The spec defines the operation for C++ and Java; Rust is not one of its language bindings.

Spec: §7.8.2.3, p. 58 — “Before sending a reply, the service implementation needs to set the related sample identity of the reply sample. […] This specification provides language bindings to set the related sample identity when sending the reply to a request.”

Repo: runtime/cpp/include/dds/rpc/core.hpp::Replier::send_reply (with related_request_id; Writer::write_related in runtime/cpp/include/dds/rpc/zerodds.hpp); runtime/java/src/main/java/org/omg/dds/rpc/Replier.java::sendReply (with relatedRequestId; DataWriter.write(sample, related)); Rust: crates/rpc/src/replier.rs::Replier::send_reply (with RequestIdentity) and crates/dcps/src/runtime.rs::DcpsRuntime::write_user_sample_related. Commits: 2bfb2786121b (C++), 771f12846807 and a2a9a67acb58 (Java), c5af5c7c138e (Rust)

Tests: crates/rpc/tests/cpp_rpc_zerodds_related_identity.rs::the_zerodds_binding_sends_and_reads_the_related_sample_identity, crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together, crates/rpc/tests/java_rpc_runtime.rs::the_java_rpc_runtime_and_the_generated_services_run_together, crates/rpc/src/replier.rs::tests::receive_requests_and_send_reply_expose_the_identity

Status: done — the replier sets the identity of the request when it sends: in the Enhanced mapping as PID_RELATED_SAMPLE_IDENTITY, in the Basic mapping in the ReplyHeader.


§7.9 Service Lifecycle

§7.9.1 Activation by creating the service or the replier

Spec: §7.9.1, p. 59 — “In Basic and Enhanced Service Mappings, when using the function-call style language binding, creating an instance of the Service type activates the service. Likewise, when using the request/reply style language binding, creating an instance of a Replier activates the service.”

Repo: crates/rpc/src/replier.rs::Replier::new; crates/lang-rules/src/emit/interface_rust.rs (dispatcher with serve); runtime/cpp/include/dds/rpc.hpp::Replier (constructor with ReplierParams); crates/lang-rules/src/emit/interface_cpp/calls.rs and crates/lang-rules/src/emit/interface_java/calls.rs (<I>Service over a Replier, created in the constructor). Commits: ec3707125a9b (C++), c512ee365514 (Java)

Tests: crates/rpc/src/replier.rs::tests::replier_new_creates_endpoints, crates/rpc-rust-e2e/tests/e2e.rs::the_generated_calculator_binding_runs_every_call, crates/rpc/tests/cpp_function_call.rs::the_generated_client_calls_the_generated_service, crates/rpc/tests/java_rpc_runtime.rs::the_generated_function_call_client_calls_the_generated_service

Status: done — creating the Replier, serve (Rust) and <I>Service (C++, Java) activates the service.

§7.9.1 Activation creates DataReader and DataWriter

Spec: §7.9.1, p. 59 — “Service activation shall result in creation of the underlying DataReader and DataWriter entities and they shall be enabled.”

Repo: crates/rpc/src/replier.rs::Replier::from_topics (create_datareader, create_datawriter); runtime/cpp/include/dds/rpc.hpp::Replier; runtime/java/src/main/java/org/zerodds/ddsrpc/ReplierImpl.java

Tests: crates/rpc-rust-e2e/tests/e2e.rs::the_generated_calculator_binding_runs_every_call, crates/rpc/tests/cpp_function_call.rs::the_generated_client_calls_the_generated_service (program function_call_roundtrip.cpp: “creating the service creates its DataReader and DataWriter”)

Status: done — the entities are created on construction and are active.

§7.9.1 Activated service is discoverable

Spec: §7.9.1, p. 59 — “An activated service shall be discoverable.”

Repo: crates/rpc/src/replier.rs::Replier::from_topics (topics under the type names ${I}_Request and ${I}_Reply; in the Enhanced mapping with the discovery extension of §7.6.2.1)

Tests: crates/rpc-rust-e2e/tests/e2e.rs::the_generated_calculator_binding_runs_every_call, crates/rpc-rust-e2e/tests/enhanced_e2e.rs::the_client_waits_for_the_service_instance_it_names, crates/rpc-rust-e2e/tests/lifecycle_e2e.rs::closing_a_service_deletes_its_entities

Status: done — the client finds the activated service through discovery (service_matched); the tests run client and service on one participant.

§7.9.2.1 Function-call: invocation of the implementation

Spec: §7.9.2.1, p. 59 — “Concrete implementations of the interface operations shall be invoked as a consequence of receiving requests. The operations must return a reply consistent with the language binding.”

Repo: crates/lang-rules/src/emit/interface_rust.rs (dispatcher_impl, dispatcher_handle_fn); crates/lang-rules/src/emit/interface_cpp/calls.rs and crates/lang-rules/src/emit/interface_java/calls.rs (<I>Service, calls the implementation and translates what it throws into a remote exception code). Commits: ec3707125a9b (C++), c512ee365514 (Java)

Tests: crates/rpc-rust-e2e/tests/e2e.rs::the_generated_calculator_binding_runs_every_call, crates/rpc/tests/cpp_function_call.rs::the_generated_client_calls_the_generated_service, crates/rpc/tests/cpp_enhanced_function_call.rs::the_generated_enhanced_client_calls_the_generated_enhanced_service, crates/rpc/tests/java_rpc_runtime.rs::the_generated_function_call_client_calls_the_generated_service, crates/lang-rules/tests/interface_bindings.rs::cpp_service_translates_what_the_implementation_throws

Status: done — in Rust, C++ and Java the generated service calls the implementation of the operation and returns the reply.

§7.9.2.2 Three ways of processing

Spec: §7.9.2.2, p. 59 — “The request/reply style language binding provides three mutually exclusive ways to process requests.”

Repo: —

Tests: —

Status: n/a (informative) — introduction; the three ways follow as items.

§7.9.2.2 Way 1: synchronous listener

Spec: §7.9.2.2, p. 59 — “1. A synchronous service listener callback can be installed during service activation. The synchronous callback must return the reply before the callback returns. It is invoked for each received request.”

Repo: crates/rpc/src/replier.rs (ReplierHandler, passed to Replier::new; Replier::tick; Replier::activate); runtime/cpp/include/dds/rpc.hpp (SimpleReplierListener, Replier::dispatch_requests, called on arrival through Replier::Impl::listen); runtime/java/src/main/java/org/omg/dds/rpc/SimpleReplierListener.java (ListenerDelivery.ON_ARRIVAL). Commits: cd07b2221f07 (Rust), 05c799d7e041 (C++), 771f12846807 (Java)

Tests: crates/rpc/src/replier.rs::tests::tick_processes_request_and_writes_reply, crates/rpc-rust-e2e/tests/lifecycle_e2e.rs::a_call_is_answered_without_anyone_ticking, crates/rpc/tests/cpp_rpc_zerodds_listener.rs::the_zerodds_reader_calls_its_callback_on_arrival_and_not_after_removal, crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together, crates/rpc/tests/java_rpc_runtime.rs::the_java_rpc_runtime_and_the_generated_services_run_together

Status: done — the listener is passed on creation, returns the reply, and is called on arrival of each request (Rust: activate; Java: depending on ListenerDelivery, default ON_ARRIVAL).

§7.9.2.2 Way 2: asynchronous listener with the replier

Spec: §7.9.2.2, p. 59 — “2. An asynchronous service listener callback can be installed during service activation. The asynchronous callback does not return the reply. The callback receives a handle to the Replier instance and the Replier API can be used to retrieve the requests and send the replies.”

Repo: crates/rpc/src/replier.rs (AsyncReplierHandler, Replier::activate_async, Replier::dispatch_async); runtime/cpp/include/dds/rpc.hpp (ReplierListener); runtime/java/src/main/java/org/omg/dds/rpc/ReplierListener.java. Commits: c5af5c7c138e and cd07b2221f07 (Rust), 05c799d7e041 (C++), 771f12846807 (Java)

Tests: crates/rpc/src/replier.rs::tests::dispatch_async_hands_the_replier_and_the_identity_to_the_listener, crates/rpc-rust-e2e/tests/lifecycle_e2e.rs::the_asynchronous_listener_is_called_as_the_request_arrives, crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together, crates/rpc/tests/java_rpc_runtime.rs::the_java_rpc_runtime_and_the_generated_services_run_together

Status: done — the callback receives the replier and returns no reply; in all three runtimes.

§7.9.2.2 Way 3: retrieve requests through the replier API

Spec: §7.9.2.2, p. 59 — “3. The Replier API may be used to retrieve the requests and send replies.”

Repo: crates/rpc/src/replier.rs (Replier::receive_requests, Replier::send_reply, Replier::send_exception); runtime/cpp/include/dds/rpc.hpp (Replier::receive_requests, Replier::send_reply); runtime/java/src/main/java/org/omg/dds/rpc/Replier.java (receiveRequests, sendReply). Commits: c5af5c7c138e (Rust), 2ea2abb7d843 (C++), 771f12846807 (Java)

Tests: crates/rpc/src/replier.rs::tests::receive_requests_and_send_reply_expose_the_identity, crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together, crates/rpc/tests/java_rpc_runtime.rs::the_java_rpc_runtime_and_the_generated_services_run_together

Status: done — the three runtimes have retrieval of requests and sending of replies. That the names of the operations differ from those of the normative C++ file (take_request, read_request, wait_for_requests) is recorded in the item “§7.11.1 Machine-readable files for C++”.

§7.9.2.2 Listeners are called when a request arrives

Spec: §7.9.2.2, p. 59 — as the three items above.

Repo: crates/rpc/src/replier.rs::Replier::activate, Replier::activate_async (listener on the request reader); runtime/cpp/include/dds/rpc.hpp::Replier (the constructor calls Impl::listen; Replier::on_arrival); runtime/java/src/main/java/org/zerodds/ddsrpc/ReplierImpl.java and ListenerDelivery.java (ON_ARRIVAL through DataReader.setDataAvailableListener). Commits: cd07b2221f07 (Rust), 05c799d7e041 (C++), 771f12846807 (Java)

Tests: crates/rpc-rust-e2e/tests/lifecycle_e2e.rs::a_call_is_answered_without_anyone_ticking, crates/rpc-rust-e2e/tests/lifecycle_e2e.rs::the_asynchronous_listener_is_called_as_the_request_arrives, crates/rpc/tests/cpp_rpc_zerodds_listener.rs::the_zerodds_reader_calls_its_callback_on_arrival_and_not_after_removal, crates/rpc/tests/java_rpc_runtime.rs::the_java_rpc_runtime_and_the_generated_services_run_together (program RpcRuntimeRoundtrip.java, section on the Java PSM: “the replier listener ran on arrival”)

Status: done — in all three runtimes the runtime calls the listener when a request arrives; the application need not call tick(), dispatch_requests() or dispatchRequests(). Java also has ListenerDelivery.ON_PUMP for a binding that cannot notify.

§7.9.3 Deactivation deletes DataReader and DataWriter

Spec: §7.9.3, p. 59 — “Deleting (subject to language binding) the service instance deactivates the service. In Java language binding, Closeable.Close() deactivates the service. In C++ language binding, the destructor of the service implementation shall deactivate the service. Deactivation shall delete the underlying DDS entities (i.e., DataReader and DataWriter only).”

Repo: crates/rpc/src/replier.rs::Replier::close (the last handle deletes the entities); runtime/cpp/include/dds/rpc.hpp::Replier::close (releases reader and writer; the destructors of the binding call zerodds_writer_destroy and zerodds_reader_destroy); runtime/java/src/main/java/org/zerodds/ddsrpc/ReplierImpl.java::close and runtime/java/src/main/java/org/zerodds/ddsrpc/RequesterImpl.java::close (DomainParticipant.deleteWriter, deleteReader). Commits: cd07b2221f07 (Rust), ec3707125a9b (C++), 530a4c8dee0a and 771f12846807 (Java)

Tests: crates/rpc-rust-e2e/tests/lifecycle_e2e.rs::closing_a_service_deletes_its_entities, crates/rpc/src/requester.rs::tests::duplicate_instance_name_freed_after_drop, crates/rpc/tests/cpp_function_call.rs::the_generated_client_calls_the_generated_service (program function_call_roundtrip.cpp: “destroying the last copy deletes the DataReader and the DataWriter”), crates/rpc/tests/java_rpc_runtime.rs::the_java_rpc_runtime_and_the_generated_services_run_together (program RpcRuntimeRoundtrip.java: “closing the service deleted its replier’s DataWriter and DataReader”)

Status: done — in Rust, C++ and Java deactivation deletes the DataReader and the DataWriter and no other entity. The Rust test checks that the peer loses the match.

§7.9.3 Deactivation in Java and in generated C++

Spec: §7.9.3, p. 59 — as above.

Repo: runtime/java/src/main/java/org/omg/dds/rpc/RPCEntity.java (Closeable); runtime/java/src/main/java/org/zerodds/ddsrpc/ZeroDdsParticipant.java (deleteWriter, deleteReader close the entities of the Java PSM); runtime/cpp/include/dds/rpc.hpp::ServiceEndpoint::close; crates/lang-rules/src/emit/interface_cpp/calls.rs (<I>Service holds the Replier, the destructor releases it). Commits: 530a4c8dee0a, ec3707125a9b (C++), c512ee365514 (Java), a2a9a67acb58

Tests: crates/rpc/tests/cpp_function_call.rs::the_generated_client_calls_the_generated_service, crates/rpc/tests/java_rpc_runtime.rs::the_generated_function_call_client_calls_the_generated_service, crates/rpc/tests/java_rpc_runtime.rs::the_java_rpc_runtime_and_the_generated_services_run_together

Status: done — close() in Java and the destructor or close() of the generated C++ classes delete the DataReader and the DataWriter. The programs of the tests count the entities deleted on a recording binding; that ZeroDdsParticipant closes the entities of the Java PSM is read from the code (psm.close()), not checked by a test.


§7.10 Service QoS

§7.10 QoS annotation on the interface

Spec: §7.10, p. 59 — “Both Basic and Enhanced Service Mappings allow QoS annotation with an interface.”

Repo: —

Tests: —

Status: n/a (informative) — introduction; the annotation is in §7.10.1.

§7.10.1 Annotation @Qos with RequestProfile and ReplyProfile

Spec: §7.10.1, pp. 59–60 — “To set the specific Qos for an interface, the annotation @Qos shall be used. It is defined as follows. @annotation local interface Qos { attribute string RequestProfile; attribute string ReplyProfile; };”

Repo: crates/rpc/src/annotations.rs (lower_single, branch "Qos"; RpcAnnotation::Qos; LoweredRpc::qos_profiles); @Qos is predefined as an annotation of the spec (commit 6c7f585a36ee); crates/lang-rules/src/adapter/interface.rs (qos_request_profile, qos_reply_profile); crates/lang-rules/src/emit/interface_rust.rs::declared_qos_fn (new_with_declared_qos, serve_with_declared_qos); crates/lang-rules/src/emit/interface_cpp/calls.rs::defaults_method; crates/lang-rules/src/emit/interface_java/calls.rs (qosProfiles). @RPCInterfaceQos(profile = …) remains as an extension next to @Qos. Commits: e0eb1bf9c607 (Rust), ec3707125a9b (C++), c512ee365514 (Java)

Tests: crates/rpc/src/annotations.rs::tests::the_spec_annotations_need_no_declaration, crates/rpc/src/qos_profile.rs::tests::the_request_and_the_reply_profile_apply_to_their_own_endpoints, crates/lang-rules/tests/interface_rust_binding.rs::the_qos_the_interface_declares_is_applied_by_a_constructor, crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together (program rpc_runtime_roundtrip.cpp: profiles of the params)

Status: done — @Qos with RequestProfile and ReplyProfile is recognised and reaches the endpoints in Rust, C++ and Java; a missing ReplyProfile makes both directions build from the RequestProfile.

§7.10.1 Profile as URL, file:// mandatory, #library_name

Spec: §7.10.1, p. 60 — “The profile attributes are string URLs of the form: ://path/resource where protocol, “:”, “//” and path are optional. Support for the file:// protocol is mandatory. If the protocol:// is omitted, the string attributes are interpreted as if the protocol is file://. The URL may end with an optional library name. The profile filename and library_name are separated by a #.”

Repo: crates/rpc/src/qos_profile.rs::RpcQos::from_qos_url (split_qos_url); crates/zerodds-c-api/src/rpc_profile_ffi.rs::zerodds_endpoint_qos_from_profile_url (C++: runtime/cpp/include/dds/rpc/zerodds.hpp); runtime/java/src/main/java/org/omg/dds/rpc/RpcQos.java::fromUrl. Commits: 152906e062f1 (Rust), a0d1af7efd77 (c-api), 7253f8222589 (C++), 771f12846807 (Java)

Tests: crates/rpc/src/qos_profile.rs::tests::split_qos_url_defaults_the_protocol_to_file, crates/rpc/src/qos_profile.rs::tests::from_qos_url_reads_the_file_and_applies_the_library, crates/zerodds-c-api/tests/rpc_qos.rs::a_profile_url_resolves_the_named_library_over_the_rpc_defaults, crates/rpc/tests/cpp_rpc_zerodds_qos.rs::the_zerodds_binding_carries_the_rpc_qos_to_the_c_api, crates/rpc/tests/java_rpc_runtime.rs::the_java_rpc_runtime_and_the_generated_services_run_together (program RpcRuntimeRoundtrip.java: RpcQos.fromUrl)

Status: done — file:// is read, without a protocol file:// applies, # separates file name and library; another protocol is an error, not a fetch.

§7.10.1 Profiles in the DDS4CCM format

Spec: §7.10.1, p. 60 — “The QoS profiles are XML QoS Profiles as defined in the [DDS4CCM] specification.”

Repo: crates/rpc/src/qos_profile.rs::RpcQos::from_xml_profile and RpcQos::from_qos_url (profiles from zerodds-xml, DDS-XML 1.0: <dds><qos_library><qos_profile>); commit: 9b74a81b0a98

Tests: crates/rpc/src/qos_profile.rs::tests::from_xml_profile_overrides_history_depth, crates/rpc/src/qos_profile.rs::tests::from_xml_profile_follows_base_name_chain, crates/rpc/tests/runtime_e2e.rs::e2e_qos_profile_from_xml_drives_history_depth

Status: done — DDS4CCM 1.1 §7.4.2.3 puts <qos_profile> directly under <dds> and knows the short form of a single <datawriter_qos name="…"> (§7.4.2.3.3); there is no qos_library there. DDS-XML 1.0 has no such form, so crates/xml treats it as a vendor form: the default refuses it with an error that names it, VendorForms::Accept reads it into the library CCM_LIBRARY ((dds)) and reports each one (crates/xml/src/qos_parser.rs::parse_ccm_top_level_profile). RpcQos::from_qos_url and zerodds_endpoint_qos_from_profile_url read the files with that setting, because §7.10.1 names DDS4CCM as the format. Commit 07a65cfe5cde. Tests: crates/xml/src/zerodds_xml.rs::tests::ccm_profiles_directly_under_dds_are_a_vendor_form, a_qos_library_and_ccm_profiles_can_share_a_document, crates/rpc/src/qos_profile.rs::tests::from_qos_url_reads_a_ddscm_profile_file, crates/zerodds-c-api/tests/rpc_qos.rs (run on the Linux test host for crates/xml).

§7.10.2 Defaults without specification

Spec: §7.10.2, p. 60 — “When no QoS is specified, default QoS are in effect. […] The users may modify the mutable QoS policies at run-time.”

Repo: crates/rpc/src/qos_profile.rs::RpcQos::default_basic; runtime/cpp/include/dds/rpc/base.hpp::EndpointQos; runtime/java/src/main/java/org/omg/dds/rpc/RpcQos.java::defaults

Tests: crates/rpc/src/qos_profile.rs::tests::default_is_basic, crates/rpc/src/qos_profile.rs::tests::default_basic_matches_spec_710_2, crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together (program: “the defaults are §7.10.2’s”), crates/rpc/tests/java_rpc_runtime.rs::the_java_rpc_runtime_and_the_generated_services_run_together (program: “§7.10.2: RELIABLE, KEEP_ALL, VOLATILE”)

Status: done — without a specification the defaults of the three policies apply in Rust, C++ and Java (following items). The change at run time is in the next item.

§7.10.2 Mutable QoS at run time

Spec: §7.10.2, p. 60 — as above.

Repo: crates/rpc/src/replier.rs::Replier::set_qos, crates/rpc/src/requester.rs::Requester::set_qos; runtime/cpp/include/dds/rpc.hpp (Requester::set_qos, Replier::set_qos, ServiceEndpoint::set_qos) through zerodds_writer_set_qos and zerodds_reader_set_qos of the C API; runtime/java/src/main/java/org/omg/dds/rpc/Requester.java::setQos, runtime/java/src/main/java/org/omg/dds/rpc/Replier.java::setQos. Commits: 5e31aafecaaf (Rust), 7253f8222589 (C++), 19814c9f2e93 (c-api: only DEADLINE and LIFESPAN are changeable), 771f12846807 (Java), 04b1846d0ee5 (Java: ZeroDdsParticipant passes the change on to the PSM)

Tests: crates/rpc/tests/runtime_e2e.rs::e2e_set_qos_changes_the_mutable_policies_at_run_time, crates/zerodds-c-api/tests/rpc_qos.rs::the_mutable_policies_of_a_live_endpoint_change_and_the_immutable_ones_are_refused, crates/rpc/tests/cpp_rpc_zerodds_qos.rs::the_zerodds_binding_carries_the_rpc_qos_to_the_c_api, crates/rpc/tests/java_rpc_runtime.rs::the_java_rpc_runtime_and_the_generated_services_run_together

Status: done — Rust and C++ change the changeable policies and refuse the immutable ones. In Java ZeroDdsParticipant.Writer.setQos (and Reader.setQos) pass the changed QoS to DataWriterImpl.setQos or DataReaderImpl.setQos of the PSM; the PSM applies the change of a changeable policy (DEADLINE, LIFESPAN) and refuses an immutable one with ImmutablePolicyException (QosRules.checkChange, 8bc25e5d19b1), which the runtime reports as RemoteUnsupportedError. Test: crates/rpc/tests/java/RpcRuntimeRoundtrip.java::overTheJavaPsm (DEADLINE changes, RELIABILITY does not; needs a JDK). The earlier statement that the PSM refuses every change held before 8bc25e5d19b1.

§7.10.2 Reliability RELIABLE

Spec: §7.10.2, p. 60 — “Reliability DDS_RELIABLE_RELIABILITY_QOS”.

Repo: crates/rpc/src/qos_profile.rs::RpcQos::default_basic; runtime/cpp/include/dds/rpc/base.hpp::EndpointQos; runtime/java/src/main/java/org/omg/dds/rpc/RpcQos.java::defaults

Tests: crates/rpc/src/qos_profile.rs::tests::default_basic_matches_spec_710_2, crates/rpc/src/qos_profile.rs::tests::writer_qos_carries_reliability_and_history, crates/rpc/src/qos_profile.rs::tests::reader_qos_carries_reliability

Status: done — default RELIABLE in Rust, C++ and Java.

§7.10.2 History KEEP_ALL

Spec: §7.10.2, p. 60 — “History DDS_KEEP_ALL_HISTORY_QOS”.

Repo: crates/rpc/src/qos_profile.rs::RpcQos::default_basic, RpcQos::default_enhanced (DEFAULT_HISTORY_QOS); runtime/cpp/include/dds/rpc/base.hpp::EndpointQos; runtime/java/src/main/java/org/omg/dds/rpc/RpcQos.java::defaults. Commit: ff6353d0ef20

Tests: crates/rpc/src/qos_profile.rs::tests::default_basic_matches_spec_710_2, crates/rpc/src/qos_profile.rs::tests::default_enhanced_uses_the_same_history, crates/rpc/src/qos_profile.rs::tests::writer_qos_carries_reliability_and_history

Status: done — default KEEP_ALL in Rust, C++ and Java.

§7.10.2 Durability VOLATILE

Spec: §7.10.2, p. 60 — “Durability DDS_VOLATILE_DURABILITY_QOS”.

Repo: crates/rpc/src/qos_profile.rs::RpcQos::default_basic; runtime/cpp/include/dds/rpc/base.hpp::EndpointQos; runtime/java/src/main/java/org/omg/dds/rpc/RpcQos.java::defaults

Tests: crates/rpc/src/qos_profile.rs::tests::default_basic_matches_spec_710_2

Status: done — default VOLATILE in Rust, C++ and Java.


§7.11 Language Bindings

§7.11 Figure 7.5 — inheritance of the RPC entities

Spec: §7.11, p. 60, Figure 7.5 — RPCEntity is the base of Server, ServiceEndpoint, Replier and ServiceProxy; ServiceProxy is the base of Requester and ClientEndpoint; ServiceEndpoint of Service; ClientEndpoint of Client.

Repo: runtime/cpp/include/dds/rpc.hpp (RPCEntity, ServiceProxy, Requester, Replier, ServiceEndpoint, ClientEndpoint, Service, Client); runtime/java/src/main/java/org/omg/dds/rpc/ (RPCEntity, ServiceProxy, Requester, Replier, ServiceEndpoint, ClientEndpoint, Service, Client). Commit: 2ea2abb7d843 (C++)

Tests: crates/rpc/tests/class_summaries_are_declared.rs::the_cpp_runtime_declares_every_class_of_the_two_summaries, crates/rpc/tests/class_summaries_are_declared.rs::the_java_package_declares_every_type_of_the_two_summaries, crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together (program rpc_runtime_roundtrip.cpp: static_assert(std::is_base_of<…>) for every relation of the figure), crates/rpc/tests/java_rpc_runtime.rs::the_java_entities_are_interfaces_and_the_runtime_makes_services_and_clients (program crates/rpc/tests/java/RpcInheritanceTest.java: Server and ClientEndpoint)

Status: done — C++: rpc_runtime_roundtrip.cpp checks every relation of the figure with std::is_base_of when it compiles, Server included (f8116b6debc1). Java: RpcInheritanceTest.java checks the base interfaces of the figure member by member (267cd1cb4793).

§7.11 Server as RPCEntity

Spec: §7.11, p. 60, Figure 7.5 — as above.

Repo: runtime/cpp/include/dds/rpc.hpp::Server (class Server : public RPCEntity, is_null(), close(), run(), run(Duration)); runtime/java/src/main/java/org/omg/dds/rpc/Server.java (Server extends RPCEntity, Runnable; run, getDefaultServiceParams, isNull, close). Commits: f8116b6debc1 (C++), 17cc6c7ad2a5 (Java)

Tests: crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together (program rpc_runtime_roundtrip.cpp: static_assert(std::is_base_of<dds::rpc::RPCEntity, dds::rpc::Server>)), crates/rpc/tests/java_rpc_runtime.rs::the_java_entities_are_interfaces_and_the_runtime_makes_services_and_clients (program crates/rpc/tests/java/RpcInheritanceTest.java: “Server extends RPCEntity”, “Server extends Runnable”, run, getDefaultServiceParams, isNull, close)

Status: done — Server is an RPCEntity in C++ and Java, as the normative files function_call.h and runtime/java/src/main/java/org/omg/dds/rpc/Server.java declare it. C++: is_null(), close(), run() and run(Duration); add refuses a service that another Server holds (IllegalOperationError). Java: ServerImpl.add refuses null, a closed service and an already bound one. The tests were read in the code; a run on the Linux test host after these commits is pending.

§7.11.1 Machine-readable files for C++

Spec: §7.11.1, p. 61 — “The machine readable files associated with this specification represent the normative language bindings for C++.”

Repo: runtime/cpp/include/dds/rpc/normative/ (the three headers unchanged), runtime/cpp/include/dds/rpc/vendor_dependent.h, runtime/cpp/include/dds/rpc/request_reply.hpp, runtime/cpp/include/dds/rpc/function_call.hpp, runtime/cpp/include/dds/rpc/core.hpp, runtime/cpp/include/dds/rpc/base.hpp, runtime/cpp/include/dds/rpc.hpp; compared with the headers request_reply, function_call and sample from omg-dds-rpc-cxx.zip

Tests: crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together (program rpc_runtime_roundtrip.cpp, namespace signatures), crates/rpc/tests/cpp_normative_headers.rs::the_shipped_headers_are_the_omg_files, crates/rpc/tests/cpp_normative_headers.rs::the_normative_headers_compile_against_vendor_dependent_h, crates/rpc/tests/cpp_normative_headers.rs::a_program_against_the_normative_headers_runs_against_libzerodds

Status: done — request_reply.h, function_call.h and sample.h of omg-dds-rpc-cxx.zip are in runtime/cpp/include/dds/rpc/normative/ unchanged (NOTICE, SHA-256 in omg-dds-rpc-cxx.sha256). vendor_dependent.h fills in what the headers call “vendor dependent” (OMG_DDS_RPC_REFERENCE_IMPLEMENTATION, dds::dds_entity_traits, details::vendor_dependent<T>, forward declarations). request_reply.hpp and function_call.hpp define the classes of the headers as handles on the implementation classes in dds::rpc::core (core.hpp, base.hpp); rpc.hpp is the layer above (Service, Client, RPCRuntime, add(Server&, …)), and the generated headers include them (f2fc6695f1e9, c56e3e21d7cc, 82edc9e2fb65, 1052b15cbe41). Measured on the Linux test host: the translation unit of both normative headers, which had 254 errors before, compiles with -Wall -Wextra -Werror; a program written against the normative headers (normative_roundtrip.cpp) runs a request/reply (Requester, Replier) and a function call (ClientEndpoint/ServiceEndpoint of the generated client and service) against libzerodds (8527130ff3fb). The SHA-256 sums of the three files are in omg-dds-rpc-cxx.sha256; the comparison with the zip runs where ZD_DDS_RPC_CXX_ZIP, internal/standards/cache/omg/ or ~/.cache/zerodds-spec/ name it; whether it was there on the test host was not checked. Two defects of the OMG headers are worked around, not changed: the private destructor of ListenerBase (while the header is read, virtual carries a public:, vendor_dependent.h) and RequesterParams used before its declaration. The headers give Server no add, run_once and size; dds::rpc::add, run_once and size in rpc.hpp add them.

§7.11.1.1.1 Request/reply: user IDL structs or synthesized ones

Spec: §7.11.1.1.1, p. 61 — “The request-reply style language binding for the Basic Service Mapping shall use either the user-defined IDL structs directly or the structs synthesized from an IDL interface.”

Repo: runtime/cpp/include/dds/rpc.hpp (Requester<TReq, TRep>, Replier<TReq, TRep> over dds_type_traits); crates/lang-rules/src/emit/interface_cpp.rs::requester_alias. Commit: ad892a10764a

Tests: crates/lang-rules/tests/interface_bindings.rs::cpp_binds_the_requester_and_replier_of_seven_eleven_one_one_one, crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together

Status: done — Requester and Replier take the structs of the user and the synthesized ones through dds_type_traits; the generator binds both (CalculatorRequester, CalculatorReplier).

§7.11.1.1.1 Mapping of IDL to C++ by [IDL35]

Spec: §7.11.1.1.1, p. 61 — “The IDL shall be mapped to C++ types as defined in [IDL35] (including the vendor-specific mappings for DDS v1.3).”

Repo: crates/lang-rules/src/adapter/cpp.rs (default: own mapping); crates/lang-rules/src/adapter/cpp_psm.rs (--cpp-mapping psm: mapping by DDS-PSM-Cxx §8.1); tools/idlc/src/main.rs (option --cpp-mapping). Commit: 1db807cbf0fb

Tests: tools/idlc/src/generate.rs::tests::the_psm_mapping_is_a_layer_over_the_native_types, crates/rpc/tests/cpp_function_call.rs::the_generated_client_calls_the_generated_service, crates/rpc/tests/cpp_enhanced_function_call.rs::the_generated_enhanced_client_calls_the_generated_enhanced_service, crates/lang-rules/tests/interface_cpp_psm_types.rs::the_enhanced_futures_hold_the_applications_types

Status: done — The default is --cpp-mapping psm (CppMapping::Psm in adapter/cpp.rs); --cpp-mapping native is a named setting. The classes <I>, <I>Async, client and service spell the types of DDS-PSM-Cxx Table 7.1 (std::wstring, std::map, ::dds::core::array) in the namespaces of the IDL and convert through zerodds::psm::Conv to the topic types, which stay native in zd_native (93962a6aac1c, test interface_cpp_psm_types.rs::the_topic_types_are_native_and_the_classes_are_the_applications). The future types of the _async operations hold the application’s types, in the Basic and in the Enhanced mapping (1240c62e4ec6). The C++ tests of this package run under the default (cpp_function_call, cpp_enhanced_function_call, cpp_rpc_real_library, cpp_rpc_runtime). Not checked: [IDL35] is not in the cache; the clause names DDS-PSM-Cxx Table 7.1 for the types.

§7.11.1.1.1 Templates to send, receive, allocate, initialize, destroy

Spec: §7.11.1.1.1, p. 61 — “The Requester, Replier, Sample, SampleRef, WriteSample, and WriteSampleRef templates provide a uniform interface to send, receive, allocate, initialize, and destroy data.”

Repo: runtime/cpp/include/dds/rpc.hpp (Sample, SampleRef, WriteSample, WriteSampleRef, Requester, Replier)

Tests: crates/rpc/tests/class_summaries_are_declared.rs::the_cpp_runtime_declares_every_class_of_the_two_summaries, crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together

Status: done — the six templates exist and carry sending (Requester::send_request), receiving (Replier::receive_requests, Requester::receive_reply), allocating and initializing (constructors) and destroying (destructors). The comparison of the individual operations with sample.h is in the item “§7.11.1 Machine-readable files for C++”.

§7.11.1.1.2 Function-call: topic types by DDS-Cxx-PSM

Spec: §7.11.1.1.2, p. 61 — “The function-call style language binding for the Basic Service Mapping shall use the structs (and unions) synthesized from the user-defined IDL interface […] The topic-types shall be mapped to C++ types as per defined in [DDS-Cxx-PSM] with the following additional rules”.

Repo: crates/lang-rules/src/emit/interface_cpp.rs::declare; crates/lang-rules/src/adapter/cpp.rs::cpp_value_type

Tests: crates/lang-rules/tests/interface_bindings.rs::cpp_declares_the_topic_types_of_seven_five, crates/rpc/tests/cpp_function_call.rs::the_generated_client_calls_the_generated_service, crates/lang-rules/tests/interface_cpp_psm_types.rs::the_enhanced_futures_hold_the_applications_types

Status: done — integers, string, sequence, T[N], wstring and map are spelled as in DDS-Cxx-PSM Table 7.1 by default (1db807cbf0fb, 93962a6aac1c; test interface_cpp_psm_types.rs::the_interface_spells_the_types_of_table_7_1). The default is --cpp-mapping psm (CppMapping::Psm in adapter/cpp.rs); --cpp-mapping native is a named setting. The topic types stay native (zd_native), the futures of the _async operations hold the application’s types (1240c62e4ec6).

§7.11.1.1.2 Rule 1: ${interface} and ${interface}Async in the module’s namespace

Spec: §7.11.1.1.2, p. 61 — “1. Each IDL interface shall map to an abstract class named “interface” andanabstractclassnamed“{interface}Async” in the same namespace corresponding to the module of the interface. If there is no module, no C++ namespace is generated.”

Repo: crates/lang-rules/src/emit/interface_cpp.rs (sync_interface, async_interface). Commit: ad892a10764a

Tests: crates/lang-rules/tests/interface_bindings.rs::cpp_declares_the_two_abstract_classes_of_rule_one

Status: done — two abstract classes in the namespace of the module; without a module no namespace.

§7.11.1.1.2 Rule 2: public virtual destructor

Spec: §7.11.1.1.2, p. 61 — “2. Both “interface” and“{interface}Async” abstract classes shall have a public virtual destructor.”

Repo: crates/lang-rules/src/emit/interface_cpp.rs (sync_interface, async_interface). Commit: ad892a10764a

Tests: crates/lang-rules/tests/interface_bindings.rs::cpp_declares_the_two_abstract_classes_of_rule_one

Status: done — virtual ~<I>() = default; and virtual ~<I>Async() = default;.

§7.11.1.1.2 Rule 3: SupportType, RequestType, ReplyType

Spec: §7.11.1.1.2, p. 61 — “3. Both “interface” and“{interface}Async” abstract classes shall have public SupportType, RequestType, and ReplyType typedefs for “interfaceSupport,”“{interface}_Request,” and “${interface}_Reply” types.”

Repo: crates/lang-rules/src/emit/interface_cpp.rs (sync_interface, async_interface, support_class). Commit: ad892a10764a

Tests: crates/lang-rules/tests/interface_bindings.rs::cpp_declares_the_two_abstract_classes_of_rule_one

Status: done — both classes have SupportType, RequestType and ReplyType.

§7.11.1.1.2 Rule 4: AsyncInterfaceType

Spec: §7.11.1.1.2, p. 61 — “4. The “interface” abstractclassshallcontainapublicAsyncInterfaceTypetypedeffor“{interface}Async.””

Repo: crates/lang-rules/src/emit/interface_cpp.rs::sync_interface; Commit ad892a10764a.

Tests: crates/lang-rules/tests/interface_bindings.rs::cpp_declares_the_two_abstract_classes_of_rule_one

Status: done

§7.11.1.1.2 Rule 5: InterfaceType

Spec: §7.11.1.1.2, p. 61 — “5. The “interfaceAsync” abstractclassshallcontainapublicInterfaceTypetypedeffor“{interface}.””

Repo: crates/lang-rules/src/emit/interface_cpp.rs::async_interface; Commit ad892a10764a.

Tests: crates/lang-rules/tests/interface_bindings.rs::cpp_declares_the_two_abstract_classes_of_rule_one

Status: done

§7.11.1.1.2 Rule 6: pure virtual functions for operations and attributes

Spec: §7.11.1.1.2, p. 61 — “6. The “${interface}” abstract class shall contain public pure virtual functions for all the operations and attributes defined in the IDL using the following rules”.

Repo: crates/lang-rules/src/emit/interface_cpp.rs (sync_interface, sync_method, attribute_method); Commit ad892a10764a.

Tests: crates/lang-rules/tests/interface_bindings.rs::cpp_declares_the_synchronous_operations_of_rule_six, crates/lang-rules/tests/interface_bindings.rs::cpp_names_an_attribute_accessor_after_the_attribute

Status: done

§7.11.1.1.2 Rule 6a: name of the operation

Spec: §7.11.1.1.2, p. 61 — “a. The name of the function shall be same as the name of the IDL operation.”

Repo: crates/lang-rules/src/emit/interface_cpp.rs::sync_method; Commit ad892a10764a.

Tests: crates/lang-rules/tests/interface_bindings.rs::cpp_declares_the_synchronous_operations_of_rule_six

Status: done

§7.11.1.1.2 Rule 6b: number and order of the arguments

Spec: §7.11.1.1.2, p. 61 — “b. The number and the order of the arguments shall be as defined in the IDL.”

Repo: crates/lang-rules/src/emit/interface_cpp.rs::sync_method; Commit ad892a10764a.

Tests: crates/lang-rules/tests/interface_bindings.rs::cpp_declares_the_synchronous_operations_of_rule_six

Status: done — rule 6h puts cxx_return in front of the arguments for a constructed return.

§7.11.1.1.2 Rule 6c: no exception specification

Spec: §7.11.1.1.2, p. 61 — “c. The functions shall not have any exception specification even if the IDL operation has an exception specification.”

Repo: crates/lang-rules/src/emit/interface_cpp.rs::sync_method (is_noexcept: false, no throw(...)); Commit ad892a10764a.

Tests: crates/lang-rules/tests/interface_bindings.rs::cpp_declares_the_synchronous_operations_of_rule_six

Status: done

§7.11.1.1.2 Rule 6d: primitive and container types by DDS-Cxx-PSM §7.4.2

Spec: §7.11.1.1.2, p. 61 — “d. The mapping of IDL primitive and container types to C++ types is provided in sub clause 7.4.2 in [DDS-Cxx-PSM].”

Repo: crates/lang-rules/src/adapter/cpp.rs::cpp_value_type and crates/lang-rules/src/adapter/cpp_psm.rs::psm_type, called from crates/lang-rules/src/emit/interface_cpp.rs::user_type and sync_method; commits ad892a10764a, 93962a6aac1c, fb51779ae3bc.

Tests: crates/lang-rules/tests/interface_bindings.rs::cpp_declares_the_synchronous_operations_of_rule_six, crates/lang-rules/tests/interface_cpp_psm_types.rs::the_interface_spells_the_types_of_table_7_1, crates/lang-rules/tests/interface_cpp_psm_types.rs::the_bodies_convert_between_the_psm_types_and_the_topic_structures, crates/rpc/tests/cpp_function_call.rs::the_generated_client_calls_the_generated_service, crates/rpc/tests/cpp_enhanced_function_call.rs::the_generated_enhanced_client_calls_the_generated_enhanced_service

Status: done — std::wstring, std::map and ::dds::core::array are in the arguments, returns and attributes of the synchronous interface; that is the default --cpp-mapping psm, --cpp-mapping native is a named setting (93962a6aac1c, test interface_cpp_psm_types.rs::the_interface_spells_the_types_of_table_7_1; the C++ runs under the default: cpp_function_call, cpp_enhanced_function_call).

§7.11.1.1.2 Rule 6e: passing by DDS-Cxx-PSM §7.4.5

Spec: §7.11.1.1.2, p. 61 — “e. The mapping of In, Out, and InOut primitive and constructed types (e.g., struct) is provided in sub clause 7.4.5 in [DDS-Cxx-PSM].”

Repo: crates/lang-rules/src/emit/interface_cpp.rs (passed, is_native); Commit ad892a10764a.

Tests: crates/lang-rules/tests/interface_bindings.rs::cpp_declares_the_synchronous_operations_of_rule_six

Status: done

§7.11.1.1.2 Rule 6f: getter and setter by DDS-Cxx-PSM §7.4.6

Spec: §7.11.1.1.2, p. 61 — “f. Getter/Setter functions for attributes in an interface is specified in sub clause 7.4.6 in [DDS-Cxx-PSM].”

Repo: crates/lang-rules/src/emit/interface_cpp.rs::attribute_method; Commit ad892a10764a.

Tests: crates/lang-rules/tests/interface_bindings.rs::cpp_names_an_attribute_accessor_after_the_attribute

Status: done

§7.11.1.1.2 Rule 6g: primitive types and enumerations by value

Spec: §7.11.1.1.2, p. 61 — “g. IDL operations that return primitive types and enumeration types the corresponding C++ function shall return the C++ type by value”.

Repo: crates/lang-rules/src/emit/interface_cpp.rs::sync_method (is_native); Commit ad892a10764a.

Tests: crates/lang-rules/tests/interface_bindings.rs::cpp_declares_the_synchronous_operations_of_rule_six

Status: done

§7.11.1.1.2 Rule 6h: constructed return as cxx_return

Spec: §7.11.1.1.2, p. 61 — “h. IDL operations that return constructed type (e.g., struct) shall map to the first parameter with name “cxx_return” of type a T& to the function and the function shall return void.”

Repo: crates/lang-rules/src/emit/interface_cpp.rs::sync_method; Commit ad892a10764a.

Tests: crates/lang-rules/tests/interface_bindings.rs::cpp_declares_the_synchronous_operations_of_rule_six

Status: done — ZeroDDS treats strings and sequences like constructed types; rules 6g and 6h do not name them.

§7.11.1.1.2 Rule 7: pure virtual asynchronous functions

Spec: §7.11.1.1.2, p. 62 — “7. The “${interface}Async” abstract class shall contain asynchronous public pure virtual functions for all the operations and attributes defined in the IDL using the following rules”.

Repo: crates/lang-rules/src/emit/interface_cpp.rs (async_interface, async_method, async_attribute_method); Commit ad892a10764a.

Tests: crates/lang-rules/tests/interface_bindings.rs::cpp_declares_the_asynchronous_operations_of_rule_seven

Status: done

§7.11.1.1.2 Rule 7a: name ${operation}_async

Spec: §7.11.1.1.2, p. 62 — “a. The name of the function shall be “${operation}_async”.”

Repo: crates/lang-rules/src/emit/interface_cpp.rs::async_method; Commit ad892a10764a.

Tests: crates/lang-rules/tests/interface_bindings.rs::cpp_declares_the_asynchronous_operations_of_rule_seven

Status: done

§7.11.1.1.2 Rule 7b: only In and InOut

Spec: §7.11.1.1.2, p. 62 — “b. The function shall accept only In and InOut parameters and shall have no Out parameters.”

Repo: crates/lang-rules/src/emit/interface_cpp.rs::async_method (operation.inputs()); Commit ad892a10764a.

Tests: crates/lang-rules/tests/interface_bindings.rs::cpp_declares_the_asynchronous_operations_of_rule_seven

Status: done

§7.11.1.1.2 Rule 7c: no exception specification

Spec: §7.11.1.1.2, p. 62 — “c. The functions shall not have any exception specification even if the IDL operation has an exception specification.”

Repo: crates/lang-rules/src/emit/interface_cpp.rs::async_method; Commit ad892a10764a.

Tests: crates/lang-rules/tests/interface_bindings.rs::cpp_declares_the_asynchronous_operations_of_rule_seven

Status: done

§7.11.1.1.2 Rule 7d: primitive and container types, all const

Spec: §7.11.1.1.2, p. 62 — “d. The mapping of IDL primitive and container types to C++ types is provided in sub clause 7.4.2 in [DDS-Cxx-PSM]. All the arguments shall be const.”

Repo: crates/lang-rules/src/emit/interface_cpp.rs::async_method (arguments through user_type); commits ad892a10764a, 93962a6aac1c.

Tests: crates/lang-rules/tests/interface_bindings.rs::cpp_declares_the_asynchronous_operations_of_rule_seven, crates/lang-rules/tests/interface_cpp_psm_types.rs::the_enhanced_futures_hold_the_applications_types, crates/lang-rules/tests/interface_cpp_psm_types.rs::the_futures_hold_the_applications_types

Status: done — all arguments are const, with the types of Table 7.1 under the default --cpp-mapping psm, and future<…> holds the application’s types (576747fa1310, 1240c62e4ec6; tests interface_cpp_psm_types.rs::the_futures_hold_the_applications_types and ::the_enhanced_futures_hold_the_applications_types).

§7.11.1.1.2 Rule 7e: In and InOut by §7.4.5, all const

Spec: §7.11.1.1.2, p. 62 — “e. The mapping of In and InOut primitive and constructed types (e.g.,struct) is provided in sub clause 7.4.5 in [DDs-Cxx-PSM]. All the arguments shall be const.”

Repo: crates/lang-rules/src/emit/interface_cpp.rs::async_method; Commit ad892a10764a.

Tests: crates/lang-rules/tests/interface_bindings.rs::cpp_declares_the_asynchronous_operations_of_rule_seven

Status: done

§7.11.1.1.2 Rule 7f: getter returns a future of the attribute type

Spec: §7.11.1.1.2, p. 62 — “f. Attribute getter functions shall take no parameters and shall return dds::rpc::future of the same type as the attribute.”

Repo: crates/lang-rules/src/emit/interface_cpp.rs (async_interface, async_attribute_method); Commit ad892a10764a.

Tests: crates/lang-rules/tests/interface_bindings.rs::cpp_names_an_attribute_accessor_after_the_attribute

Status: done

§7.11.1.1.2 Rule 7g: setter returns future

Spec: §7.11.1.1.2, p. 62 — “g. Attribute setter functions shall take a parameter as per specified in sub clause 7.4.6 in [DDS-Cxx-PSM]. It shall return a dds::rpc::future.”

Repo: crates/lang-rules/src/emit/interface_cpp.rs (async_interface, async_attribute_method); Commit ad892a10764a.

Tests: crates/lang-rules/tests/interface_bindings.rs::cpp_names_an_attribute_accessor_after_the_attribute

Status: done

§7.11.1.1.2 Rule 7h: return as a future of the type

Spec: §7.11.1.1.2, p. 62 — “h. Operation that produce a return value in the form of a regular return (primitive or constructed type) shall return a value of dds::rpc::future of that type.”

Repo: crates/lang-rules/src/emit/interface_cpp.rs::async_method; Commit ad892a10764a.

Tests: crates/lang-rules/tests/interface_bindings.rs::cpp_declares_the_asynchronous_operations_of_rule_seven

Status: done

§7.11.1.1.2 Rule 7i: future of the Out structure or future

Spec: §7.11.1.1.2, p. 62 — “i. Operation that produces return values with one or more Out/InOut parameters shall return a value of dds::rpc::future of “${interface}_${operation}_Out” type. Otherwise, it will return dds::rpc::future.”

Repo: crates/lang-rules/src/emit/interface_cpp.rs::async_method (async_payload, has_outputs); Commit ad892a10764a.

Tests: crates/lang-rules/tests/interface_bindings.rs::cpp_declares_the_asynchronous_operations_of_rule_seven

Status: done

§7.11.1.1.2 — differences from Table 7.1

Spec: §7.11.1.1.2, pp. 61–62 — rules 6d and 7d; DDS-Cxx-PSM §7.4.2, Table 7.1: “string std::wstring”, “map<K, V> std::map<K, V>”, “T[N] dds::core::array<T, N>”.

Repo: crates/lang-rules/src/emit/interface_cpp.rs (user_type, converted, async_payload), crates/lang-rules/src/adapter/cpp_psm.rs::psm_type, crates/cpp/include/zerodds/psm/convert.hpp (zerodds::psm::Conv); commits 1db807cbf0fb, 93962a6aac1c, fb51779ae3bc.

Tests: crates/lang-rules/tests/interface_cpp_psm_types.rs::the_interface_spells_the_types_of_table_7_1, crates/lang-rules/tests/interface_cpp_psm_types.rs::the_native_mapping_keeps_the_native_spelling, crates/lang-rules/tests/interface_cpp_psm_types.rs::the_bodies_convert_between_the_psm_types_and_the_topic_structures, crates/lang-rules/tests/interface_cpp_psm_types.rs::the_header_compiles, crates/lang-rules/tests/interface_cpp_psm_types.rs::the_enhanced_futures_hold_the_applications_types

Status: done — Under the default --cpp-mapping psm the abstract interface, client and service spell the rows of Table 7.1 (std::wstring, std::map, ::dds::core::array) and convert in the bodies with zerodds::psm::Conv to the topic types. The futures of the _async functions and of the attribute accessors hold the application’s types, and the Out structure is the application’s, in the Basic mapping (576747fa1310, 9ee81a26e23b) and in the Enhanced mapping (1240c62e4ec6, test interface_cpp_psm_types.rs::the_enhanced_futures_hold_the_applications_types; the Linux test host compiles both versions in the_header_compiles). --cpp-mapping native spells the native types and is a named setting.

§7.11.1.1.2 Rule 8: prefix cxx_ for reserved words

Spec: §7.11.1.1.2, p. 62 — “8. Any identifier (e.g., parameter, operation name, exception, interface, module) in an IDL file that is a reserved word in C++ shall be prefixed by “cxx_”.”

Repo: crates/lang-rules/src/emit/interface_cpp.rs::cxx_escape (calls crates/lang-rules/src/adapter/cpp.rs::cxx_name); Commits ad892a10764a (interface, operation, parameter), 688eb96e852a (exception), cdb7355e3744 (module, types).

Tests: crates/lang-rules/tests/interface_bindings.rs::cpp_prefixes_a_reserved_word_with_cxx, crates/lang-rules/tests/interface_bindings.rs::cpp_names_a_reserved_exception_with_the_cxx_prefix, crates/lang-rules/tests/interface_bindings.rs::cpp_names_a_reserved_module_and_type_with_the_cxx_prefix

Status: done — interface, operation, parameter, exception, module, declared type, members, enumerators and constants get cxx_ (item “members, enumerators and constants” below, commit d750a045b9fe).

§7.11.1.1.2 Rule 8 — members, enumerators and constants

Spec: §7.11.1.1.2, p. 62 — as above.

Repo: crates/lang-rules/src/adapter/cpp.rs::cxx_name, called for members (structure, union, exception, bitset), enumerators and constants; commit d750a045b9fe.

Tests: crates/lang-rules/tests/cxx_prefix_members.rs::a_member_that_is_a_reserved_word_is_prefixed_by_cxx, crates/lang-rules/tests/cxx_prefix_members.rs::an_enumerator_and_a_constant_that_are_reserved_words_are_prefixed_by_cxx, crates/lang-rules/tests/cxx_prefix_members.rs::the_codec_refers_to_the_prefixed_member, crates/lang-rules/tests/cxx_prefix_members.rs::the_idl_names_table_maps_the_prefixed_name_back_to_the_idl_spelling

Status: done — long static; becomes std::int32_t cxx_static;; enumerators and constants get cxx_. The codec and the _idl_names tables use the prefixed name and map back to the IDL spelling.

§7.11.1.2 Enhanced: request/reply

Spec: §7.11.1.2, p. 62 — “The request-reply style language binding for the Enhanced Service Mapping shall use either the user-defined IDL structs directly or the structs synthesized from an IDL interface. The IDL shall be mapped to C++ types as defined in [DDS-Cxx-PSM].”

Repo: runtime/cpp/include/dds/rpc.hpp (Requester<TReq, TRep>, Replier<TReq, TRep>); crates/lang-rules/src/emit/interface_cpp/enhanced.rs; Commits 45ead22cc2b9, 2ea2abb7d843.

Tests: crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together, crates/rpc/tests/cpp_enhanced_function_call.rs::the_generated_enhanced_client_calls_the_generated_enhanced_service, crates/lang-rules/tests/enhanced_cpp_calls.rs::the_enhanced_header_compiles

Status: done — the templates take the structures of the Enhanced mapping (enhanced.rs writes them, Correlation::SAMPLE_IDENTITY). The mapping of the IDL types to C++ follows DDS-Cxx-PSM Table 7.1 under the default --cpp-mapping psm (item “§7.11.1.2 — deviations from Table 7.1”).

§7.11.1.2 Enhanced: function-call by §7.11.1.1.2

Spec: §7.11.1.2, p. 62 — “The function-call style language binding for the Enhanced Service Mapping shall use the mapping rules defined in 7.11.1.1.2 Function-Call Style Language Binding.”

Repo: crates/lang-rules/src/emit/interface_cpp.rs (sync_interface, async_interface), crates/lang-rules/src/emit/interface_cpp/calls.rs; Commit 45ead22cc2b9.

Tests: crates/lang-rules/tests/enhanced_cpp_calls.rs::the_function_call_classes_are_written_over_the_choice_structures, crates/lang-rules/tests/enhanced_cpp_calls.rs::a_derived_interface_answers_the_inherited_operation_itself, crates/rpc/tests/cpp_enhanced_function_call.rs::the_generated_enhanced_client_calls_the_generated_enhanced_service, crates/lang-rules/tests/interface_cpp_psm_types.rs::the_enhanced_futures_hold_the_applications_types

Status: done — abstract classes, client and service exist for the Enhanced mapping. Rules 6d and 7d hold as in the Basic mapping: Table 7.1 under the default --cpp-mapping psm, and future<…> holds the application’s types (1240c62e4ec6, test interface_cpp_psm_types.rs::the_enhanced_futures_hold_the_applications_types).

§7.11.1.3 Local exceptions by DDS-Cxx-PSM §7.5.5

Spec: §7.11.1.3, p. 62 — “The C++ language binding may throw locally generated and remotely generated exceptions. As such, all DDS exceptions defined in sub clause 7.5.5 in [DDS-Cxx-PSM] are valid exceptions.”

Repo: runtime/cpp/include/dds/rpc.hpp (LocalError and ten derived classes: NullReferenceError, AlreadyClosedError, IllegalOperationError, PreconditionNotMetError, OutOfResourcesError, TimeoutError, ImmutablePolicyError, InconsistentPolicyError, UnsupportedError, InvalidArgumentError); Commit 2ea2abb7d843.

Tests: crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together

Status: done — local errors throw these classes in dds::rpc, named after the classes of DDS-Cxx-PSM §7.5.5 (2ea2abb7d843). With crates/cpp/include on the path (ZERODDS_RPC_HAS_DDS_CORE_EXCEPTION), each class derives from the class of the same name in dds::core (through the virtual base dds::core::Exception; crates/cpp/include/dds/core/Exception.hpp derives virtually for it): a catch (const dds::core::TimeoutError&) catches dds::rpc::TimeoutError, and so does catch (const dds::core::Exception&) (edb565cfcd88). A C API status with no class assigned throws UnspecifiedError. Test: static_asserts and catch cases in crates/rpc/tests/cpp/rpc_runtime_roundtrip.cpp, run by crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together (Linux test host, green). Without crates/cpp/include on the path the classes of DDS-Cxx-PSM do not exist and the base is std::runtime_error.

§7.11.1.3 Table: codes to exceptions

Spec: §7.11.1.3, p. 63 — “REMOTE_EX_OK No exception; REMOTE_EX_UNSUPPORTED dds::rpc::RemoteUnsupportedError; REMOTE_EX_INVALID_ARGUMENT dds::rpc::RemoteInvalidArgumentError; REMOTE_EX_OUT_OF_RESOURCES dds::rpc::RemoteOutOfResourcesError; REMOTE_EX_UNKNOWN_OPERATION dds::rpc::RemoteUnknownOperationError; REMOTE_EX_UNKNOWN_EXCEPTION dds::rpc::RemoteUnknownExceptionError”.

Repo: runtime/cpp/include/dds/rpc/base.hpp::raise_remote_exception; crates/rpc/src/language_binding.rs::cpp_exception_class; Commits ad892a10764a, 2fe2b7cdea14 (six codes).

Tests: crates/rpc/src/language_binding.rs::tests::the_table_of_seven_eleven_one_three_is_the_published_one, crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together

Status: done

§7.11.1.3 Figure 7.6 — inheritance of the exceptions

Spec: §7.11.1.3, p. 63, Figure 7.6 — RemoteOutOfResourcesError under std::runtime_error; RemoteUnsupportedError, RemoteUnknownOperationError, RemoteUnknownExceptionError under std::logic_error; RemoteInvalidArgumentError under std::invalid_argument; the classes of the right column additionally under dds::core::Exception.

Repo: runtime/cpp/include/dds/rpc.hpp (RemoteOutOfResourcesError, RemoteUnsupportedError, RemoteInvalidArgumentError, RemoteUnknownOperationError, RemoteUnknownExceptionError, detail::ExceptionRoot); commits ad892a10764a, f8116b6debc1.

Tests: crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together

Status: done — the bases from std:: match; all five classes also derive from detail::ExceptionRoot, which is dds::core::Exception when dds/core/Exception.hpp is on the include path (static_assert(std::is_base_of<…>) in check_exception_hierarchy of rpc_runtime_roundtrip.cpp; cpp_rpc_runtime.rs passes crates/cpp/include).

§7.11.1.3 Base dds::core::Exception

Spec: §7.11.1.3, p. 63, Figure 7.6 — as above.

Repo: runtime/cpp/include/dds/rpc.hpp (detail::ExceptionRoot, ZERODDS_RPC_HAS_DDS_CORE_EXCEPTION, LocalError); crates/cpp/include/dds/core/Exception.hpp; commit f8116b6debc1.

Tests: crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together

Status: done — rpc.hpp includes dds/core/Exception.hpp when __has_include finds it; detail::ExceptionRoot is then dds::core::Exception. Without the PSM headers a class of the same shape (what()) stands there. check_exception_hierarchy checks the five Remote*Error classes and LocalError with static_assert.

§7.11.1.4.1 Namespaces dds and dds::rpc with 22 classes

Spec: §7.11.1.4.1, p. 64 — “The dds, and dds::rpc namespaces define the classes and functions for the request-reply style language bindings. Specifically, the language binding includes RPCEntity, Requester, Replier, ServiceProxy, ListenerBase, SimpleReplierListener, ReplierListener, SimpleRequesterListener, RequesterListener, RequesterParams, ReplierParams, future, shared_future, Sample, SampleRef, WriteSample, WriteSampleRef, LoanedSamples, SharedSamples, SampleIterator, dds_type_traits, and dds_entity_traits.”

Repo: runtime/cpp/include/dds/rpc.hpp; crates/rpc/src/language_binding.rs (CPP_NAMESPACES, CPP_REQUEST_REPLY_CLASSES); Commits ad892a10764a, 2ea2abb7d843.

Tests: crates/rpc/tests/class_summaries_are_declared.rs::the_cpp_runtime_declares_every_class_of_the_two_summaries

Status: done

§7.11.1.4.1 Binding independent of the profile

Spec: §7.11.1.4.1, p. 64 — “C++ request-reply language binding uses templates. […] Depending upon the profile in use (Basic/Enhanced), the actual structure of the TReq and TRep types will vary. However, the request-reply language binding is independent of the profile in use.”

Repo: runtime/cpp/include/dds/rpc.hpp (Requester<TReq, TRep>, Replier<TReq, TRep>, Correlation); Commits ad892a10764a, 45ead22cc2b9.

Tests: crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together, crates/rpc/tests/cpp_enhanced_function_call.rs::the_generated_enhanced_client_calls_the_generated_enhanced_service

Status: done — the same templates carry the structures of the Basic mapping (Correlation::HEADER) and of the Enhanced mapping (Correlation::SAMPLE_IDENTITY).

§7.11.1.4.2 RPCEntity with close() and is_null()

Spec: §7.11.1.4.2, p. 64 — “RPCEntity is the base abstract class extended by all the active RPC entities. It supports close() and is_null() operations.”

Repo: runtime/cpp/include/dds/rpc/base.hpp::RPCEntity (derived: ServiceProxy, ServiceEndpoint, Server); commits ad892a10764a, f8116b6debc1.

Tests: crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together

Status: done — close() and is_null() are pure virtual in RPCEntity; Requester, Replier, ServiceEndpoint and Server derive from it (static_assert(std::is_base_of<dds::rpc::RPCEntity, …>) in rpc_runtime_roundtrip.cpp).

§7.11.1.4.3 Requester sends requests and receives replies

Spec: §7.11.1.4.3, p. 64 — “A requester sends requests and receives replies.”

Repo: runtime/cpp/include/dds/rpc.hpp::Requester; Commit ad892a10764a.

Tests: crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together

Status: done

§7.11.1.4.3 Requester is a reference type

Spec: §7.11.1.4.3, p. 64 — “Requester is a reference type and when copied it makes a shallow copy.”

Repo: runtime/cpp/include/dds/rpc.hpp::Requester (std::shared_ptr<Impl>, ServiceProxy::Binding); Commit 2ea2abb7d843.

Tests: crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together

Status: done — a copy shares Impl (writer, reader, replies, outstanding futures) and the instance binding; close() on a copy closes for all.

§7.11.1.4.3 Configuration through RequesterParams

Spec: §7.11.1.4.3, p. 64 — “An instance of a Requester is configured at the time of construction using RequesterParams, which is a container of configuration parameters, such as domain participant, QoS, listeners and more.”

Repo: runtime/cpp/include/dds/rpc.hpp (EndpointParams, RequesterParams, Requester(const RequesterParams&)); Commits 2ea2abb7d843, 7253f8222589 (QoS), 05c799d7e041 (listener).

Tests: crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together, crates/rpc/tests/cpp_rpc_zerodds_qos.rs::the_zerodds_binding_carries_the_rpc_qos_to_the_c_api

Status: done — RequesterParams carries participant, publisher, subscriber, topic names, service and instance name, RpcQos or profile URLs, and a listener.

§7.11.1.4.3 Reception through listener, polling and future

Spec: §7.11.1.4.3, p. 64 — “Requester allows listener-based, polling-based, and future-based reception of replies. […] Future-based notification of replies is analogous to callback-based notification, however, no request-reply correlation is necessary because every future represents a reply to a unique request.”

Repo: runtime/cpp/include/dds/rpc.hpp (Requester::receive_replies, receive_reply, send_request_async, dispatch_replies, constructor with impl_->listen); Commits ad892a10764a, 05c799d7e041 (listener and future on arrival).

Tests: crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together, crates/rpc/tests/cpp_rpc_zerodds_listener.rs::the_zerodds_reader_calls_its_callback_on_arrival_and_not_after_removal

Status: done

§7.11.1.4.3 Bound requester reaches only its instance

Spec: §7.11.1.4.3, p. 64 — “A requester reference may be bound to a specific service instance. Requests sent through a bound requester reference shall be sent to the bound service instance only.”

Repo: runtime/cpp/include/dds/rpc.hpp (ServiceProxy::bind, Requester::Impl::send_locked sets RequestHeader::instance_name, Replier::Impl::receive_requests filters); crates/rpc/src/replier.rs::Replier::tick; Commits 35aa702e4900 (filter), 2ea2abb7d843 (shared binding).

Tests: crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together, crates/rpc/src/replier.rs::tests::tick_filters_requests_for_other_instance_name, crates/rpc/src/replier.rs::tests::a_named_replier_does_not_answer_a_request_without_an_instance, crates/rpc/tests/runtime_e2e.rs::e2e_instance_routing_filters_per_replier

Status: done — Basic profile: the request carries the instance name in its header; a replier with a different name discards it (strict equality, the empty name matches only the empty name), also on the dispatch_requests path. Enhanced profile: item below.

§7.11.1.4.3 Binding to the instance in the Enhanced profile

Spec: §7.11.1.4.3, p. 64 — as above.

Repo: runtime/cpp/include/dds/rpc.hpp (Requester::Impl::send_locked, readers_of_instance, DataWriter::write_to); runtime/cpp/include/dds/rpc/zerodds.hpp::write_to; crates/zerodds-c-api (zerodds_writer_write_to_readers, zerodds_writer_next_sequence_number); crates/dcps (DcpsRuntime::write_user_sample_to_readers); crates/rtps (CacheChange::destination_readers); commits 6289b73b7853, 94181922bf32, 95c934ae90bc.

Tests: crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together, crates/zerodds-c-api/tests/write_to_readers.rs::a_sample_written_to_one_reader_reaches_that_reader_only, crates/rtps/src/reliable_writer.rs::tests::a_change_for_one_reader_reaches_the_other_readers_of_its_participant_as_a_gap

Status: done — the request of the Enhanced mapping carries no name; Requester::Impl::send_locked writes with write_to only to the readers that announced the instance name. The other readers of the same participant receive the change as a gap. check_instance_addressing in rpc_runtime_roundtrip.cpp checks two named repliers and the unnamed one (in-memory loop); write_to_readers.rs checks delivery through the C API. Limit: TRANSIENT_LOCAL retention does not know the addressees; the RPC QoS is VOLATILE (§7.10.2). An unbound Enhanced request in discovery mode goes only to readers without a name. Without discovery of the extension the requester refuses a bound request with UnsupportedError (read from the code).

§7.11.1.4.4 ServiceProxy

Spec: §7.11.1.4.4, p. 64 — “ServiceProxy class defines type-independent operations for Requester and the Client. For example, binding to a specific instance, waiting for an instance to discover, closing the service, and more. ServiceProxy shall not be instantiated directly.”

Repo: runtime/cpp/include/dds/rpc.hpp::ServiceProxy (bind, unbind, wait_for_service, protected constructor); Commits ad892a10764a, 2ea2abb7d843.

Tests: crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together

Status: done — wait_for_service() checks whether the service was discovered; the overload with a timeout waits for it.

§7.11.1.4.5 Replier

Spec: §7.11.1.4.5, p. 64 — “A replier receives requests and send replies. Replier is a reference type and it is inexpensive to copy […] An instance of Replier is configured at the time of construction using ReplierParams, which is a container of configuration parameters such as domain participant, QoS, listeners and more. Replier allows listener-based and polling-based reception of requests.”

Repo: runtime/cpp/include/dds/rpc.hpp::Replier (std::shared_ptr<Impl>, receive_requests, send_reply, dispatch_requests, set_qos); Commits ad892a10764a, 2ea2abb7d843, 7253f8222589, 05c799d7e041.

Tests: crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together, crates/rpc/tests/cpp_rpc_zerodds_listener.rs::the_zerodds_reader_calls_its_callback_on_arrival_and_not_after_removal

Status: done — reference type with shared Impl; ReplierParams carries participant, QoS and listener; reception through listener (on arrival) and polling.

§7.11.1.4.6 ListenerBase

Spec: §7.11.1.4.6, p. 65 — “ListenerBase is a “marker” abstract base class, which all generic listener abstract classes inherit from. It defines no member functions.”

Repo: runtime/cpp/include/dds/rpc/base.hpp::ListenerBase (only the virtual destructor); Commit ad892a10764a.

Tests: crates/rpc/tests/class_summaries_are_declared.rs::the_cpp_runtime_declares_every_class_of_the_two_summaries

Status: done ### §7.11.1.4.7 SimpleReplierListener

Spec: §7.11.1.4.7, p. 65 — “SimpleReplierListener<TReq, TRep> is used to provide a synchronous request listener for a Replier. ReplierParams is used to pass an instance […] the callback provides the request object and expects the reply as the return value.”

Repo: runtime/cpp/include/dds/rpc/base.hpp::SimpleReplierListener (process_request); commit ad892a10764a, call on arrival 05c799d7e041

Tests: crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together

Status: done

§7.11.1.4.8 ReplierListener

Spec: §7.11.1.4.8, p. 65 — “ReplierListener<TReq, TRep> interface is used to provide an asynchronous request listener for a Replier. […] the callback provides the Replier object and returns void.”

Repo: runtime/cpp/include/dds/rpc/base.hpp::ReplierListener (on_request_available(Replier&)); commit ad892a10764a, call on arrival 05c799d7e041

Tests: crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together

Status: done

§7.11.1.4.9 SimpleRequesterListener

Spec: §7.11.1.4.9, p. 65 — “SimpleRequesterListener abstract class is used to receive notifications of arrival of replies. […] the callback provides access to the reply sample and returns void.”

Repo: runtime/cpp/include/dds/rpc/base.hpp::SimpleRequesterListener (process_reply); commit ad892a10764a, call on arrival 05c799d7e041

Tests: crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together

Status: done

§7.11.1.4.10 RequesterListener

Spec: §7.11.1.4.10, p. 65 — “RequesterListener<TReq,TRep> interface is used to receive notification of reply arrival. […] the callback provides the replier object and returns void.”

Repo: runtime/cpp/include/dds/rpc/base.hpp::RequesterListener (on_reply_available(Requester&)); commit ad892a10764a, call on arrival 05c799d7e041

Tests: crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together

Status: done — the callback receives the requester; the specification writes “replier object”.

§7.11.1.4.11 RequesterParams

Spec: §7.11.1.4.11, p. 65 — “RequesterParams is a valuetype that serves as a container of configuration parameters of a Requester.”

Repo: runtime/cpp/include/dds/rpc.hpp::RequesterParams; commit ad892a10764a, shape per §7.11.1.3 to §7.11.1.5 2ea2abb7d843, QoS 7253f8222589

Tests: crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together

Status: done

§7.11.1.4.12 ReplierParams

Spec: §7.11.1.4.12, p. 65 — “ReplierParams is a valuetype that serves as a container of configuration parameters of a Replier.”

Repo: runtime/cpp/include/dds/rpc.hpp::ReplierParams; commit ad892a10764a, shape per §7.11.1.3 to §7.11.1.5 2ea2abb7d843, QoS 7253f8222589

Tests: crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together

Status: done

§7.11.1.4.13 future

Spec: §7.11.1.4.13, p. 65 — “In C++11 and C++14 environments, dds::rpc::future is a typedef for std::future. […] Future is not copyable but it is movable.”

Repo: runtime/cpp/include/dds/rpc.hpp (using future = std::future<T>); commit ad892a10764a

Tests: crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together

Status: done

§7.11.1.4.14 shared_future

Spec: §7.11.1.4.14, p. 65 — “shared_future is closely related to future and the only difference is that shared_future is copyable and movable.”

Repo: runtime/cpp/include/dds/rpc.hpp (using shared_future = std::shared_future<T>); commit ad892a10764a

Tests: crates/rpc/tests/class_summaries_are_declared.rs::the_cpp_runtime_declares_every_class_of_the_two_summaries

Status: done

§7.11.1.4.15 Sample

Spec: §7.11.1.4.15, p. 65 — “Sample is a valetype that combines a value of type T and a value of type SampleInfo. Sample is conceptually immutable.”

Repo: runtime/cpp/include/dds/rpc.hpp::Sample (read-only accessors); commit ad892a10764a

Tests: crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together

Status: done

§7.11.1.4.16 SampleRef

Spec: §7.11.1.4.16, p. 65 — “SampleRef is a reference type that combines a value of type T and a value of type SampleInfo. Copying SampleRef makes a shall copy.”

Repo: runtime/cpp/include/dds/rpc/base.hpp::SampleRef (over std::shared_ptr<Sample<T>>); commit ad892a10764a

Tests: crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together

Status: done

§7.11.1.4.17 WriteSample

Spec: §7.11.1.4.17, p. 66 — “WriteSample is a valuetype that combines a value of type T and a value of type dds::SampleIdentity. The user populates the value of T and the middleware populates the value of dds::SampleIdentity. When a request is sent as a WriteSample, upon function return, the WriteSample.identity()uniquely identifies the request sent.”

Repo: runtime/cpp/include/dds/rpc.hpp (WriteSample; Requester::send_request(WriteSample<TReq>&)); commit ad892a10764a

Tests: crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together

Status: done

§7.11.1.4.18 WriteSampleRef

Spec: §7.11.1.4.18, p. 66 — “WriteSampleRef is a reference type, which groups a reference to T and a value of type dds::SampleIdentity. […] When a request is sent as a WriteSampleRef, upon function return, the WriteSample.identity()uniquely identifies the request sent.”

Repo: runtime/cpp/include/dds/rpc/base.hpp::WriteSampleRef (over std::shared_ptr<WriteSample<T>>); commit ad892a10764a

Tests: crates/rpc/tests/class_summaries_are_declared.rs::the_cpp_runtime_declares_every_class_of_the_two_summaries, crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together

Status: done — sending as a WriteSampleRef is in the item below.

§7.11.1.4.18 Sending as WriteSampleRef

Spec: §7.11.1.4.18, p. 66 — as above.

Repo: runtime/cpp/include/dds/rpc/core.hpp::Requester::send_request(WriteSampleRef<TReq>); commit 2ea2abb7d843

Tests: crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together (program crates/rpc/tests/cpp/rpc_runtime_roundtrip.cpp: after sending, the identity is in the sample the reference refers to)

Status: done

§7.11.1.4.19 LoanedSamples

Spec: §7.11.1.4.19, p. 66 — “LoanedSamples is conceptually a container of loaned Sample from the middleware. LoanedSamples is not copyable but it is movable. LoanedSamples::value_type is SampleRef. Upon destruction, LoanedSamples returns the loaned samples to the middleware.”

Repo: runtime/cpp/include/dds/rpc/base.hpp::LoanedSamples (copy deleted, move allowed); commit ad892a10764a

Tests: crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together

Status: done — the samples are copies; there is nothing to return.

§7.11.1.4.20 SharedSamples

Spec: §7.11.1.4.20, p. 66 — “All copies of a SharedSamples refer to the same set of loaned samples. SharedSamples::value_type is SampleRef. […] Note that SharedSamples can be obtained from LoanedSample but not vice versa.”

Repo: runtime/cpp/include/dds/rpc.hpp (SharedSamples; LoanedSamples::to_shared); commit ad892a10764a

Tests: crates/rpc/tests/class_summaries_are_declared.rs::the_cpp_runtime_declares_every_class_of_the_two_summaries

Status: done

§7.11.1.4.21 SampleIterator

Spec: §7.11.1.4.21, p. 66 — “SampleIterator is a random-access iterator over LoanedSamples and SharedSamples. SampleIterator::value_type is a SampleRef.”

Repo: runtime/cpp/include/dds/rpc/base.hpp::SampleIterator (std::random_access_iterator_tag); commit ad892a10764a

Tests: crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together

Status: done

§7.11.1.4.22 dds_type_traits

Spec: §7.11.1.4.22, p. 66 — “dds_type_traits is a collection of meta-functions that given a type T, provides commonly needed dependent types, such as a DataReader for T, DataWriter for T, Sample, LoanedSamples, etc.”

Repo: runtime/cpp/include/dds/rpc/base.hpp::dds_type_traits_base (Seq, ConstSeq, DataReader, DataWriter, SampleRefType, LoanedSamplesType, SharedSamplesType, iterator, const_iterator); dds_type_traits<T> derives from dds_type_traits_base<T>, and so do the generated specialisations (crates/lang-rules/src/emit/type_pair_cpp.rs, crates/lang-rules/src/emit/interface_cpp/codec.rs, crates/lang-rules/src/emit/interface_cpp/enhanced_codec.rs); commit f8116b6debc1

Tests: crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together (static_assert in crates/rpc/tests/cpp/rpc_runtime_roundtrip.cpp on Seq, DataReader, LoanedSamplesType, SharedSamplesType, iterator, const_iterator)

Status: done — DataReader and DataWriter are the byte-oriented types of the runtime (std::shared_ptr<::dds::rpc::DataReader>), not the types of a DDS C++ library.

§7.11.1.4.23 dds_entity_traits

Spec: §7.11.1.4.23, p. 66 — “dds_entity_traits abstracts over the DDS entity types and provides consistent syntax to get DDS entity types irrespective of the DDS C++ language bindings. (e.g., DomainParticipant, Publisher, Subscriber, DataReaderQos, and DataWriterQos).”

Repo: runtime/cpp/include/dds/rpc/base.hpp::dds_entity_traits (DomainParticipant, Publisher, Subscriber, DataWriter, DataReader, DataWriterQos, DataReaderQos); commit ad892a10764a, publisher, subscriber and QoS types 2ea2abb7d843

Tests: crates/rpc/tests/class_summaries_are_declared.rs::the_cpp_runtime_declares_every_class_of_the_two_summaries, crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together (static_assert in crates/rpc/tests/cpp/rpc_runtime_roundtrip.cpp on DataWriterQos, Publisher, Subscriber)

Status: done

§7.11.1.4.23 dds_entity_traits: publisher, subscriber and QoS types

Spec: §7.11.1.4.23, p. 66 — as above.

Repo: runtime/cpp/include/dds/rpc/base.hpp::dds_entity_traits; commit 2ea2abb7d843

Tests: crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together

Status: done — Publisher and Subscriber are named, DataWriterQos and DataReaderQos are EndpointQos.

§7.11.1.5 Classes of the function-call style

Spec: §7.11.1.5, p. 66 — “Service, ServiceEndpoint, Server, Client, and ClientEndpoint classes are specific to the function-call style language binding and are described below.”

Repo: runtime/cpp/include/dds/rpc.hpp; crates/rpc/src/language_binding.rs::CPP_FUNCTION_CALL_CLASSES; commit ad892a10764a

Tests: crates/rpc/tests/class_summaries_are_declared.rs::the_cpp_runtime_declares_every_class_of_the_two_summaries

Status: done

§7.11.1.5.1 Service

Spec: §7.11.1.5.1, p. 66 — “Service is a reference type and accepts a reference to the service implementation. A Service instantiates the underlying DDS entities and makes the service discoverable. Every Service inherits from ServiceEndpoint. A Service may belong to only one Server.”

Repo: runtime/cpp/include/dds/rpc.hpp::Service (claim, release_claim); crates/lang-rules/src/emit/interface_cpp/calls.rs::service_class (<I>Service derives from dds::rpc::Service, takes <I>& and ServiceParams, creates the replier); commit ec3707125a9b, membership of a server f8116b6debc1

Tests: crates/lang-rules/tests/interface_bindings.rs::cpp_binds_the_function_call_entities_of_seven_eleven_one_five, crates/rpc/tests/cpp_function_call.rs::the_generated_client_calls_the_generated_service (program crates/rpc/tests/cpp/function_call_roundtrip.cpp: a service that a server holds is refused with IllegalOperationError by a second server and a second time by the same server)

Status: done — reference type (copies share the entities), reference to the implementation, entities and the ServiceEndpoint base match; Server::add refuses a service that already belongs to a server.

§7.11.1.5.2 ServiceEndpoint

Spec: §7.11.1.5.2, p. 67 — “A ServiceEndpoint provides type-independent functions to manage a service (e.g., pause, resume, close, etc.) A ServiceEndpoint shall not be instantiated directly; it can be obtained from a Service object. ServiceEndpoint is a reference type.”

Repo: runtime/cpp/include/dds/rpc.hpp::ServiceEndpoint (pause, resume, close, set_qos, protected constructor, state through std::shared_ptr); commit ad892a10764a

Tests: crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together

Status: done

§7.11.1.5.3 Server

Spec: §7.11.1.5.3, p. 67 — “A Server is a container of one or more Services. Server.run() function begins dispatching the requests to the Service implementation. Server is a reference type.”

Repo: runtime/cpp/include/dds/rpc.hpp::Server (add, run_once, run(), run(until), run(Duration), close, is_null, default_service_params; the services are in a shared state, copies share it; Server inherits from RPCEntity); commit ad892a10764a, base, run() and membership f8116b6debc1

Tests: crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together, crates/rpc/tests/cpp_function_call.rs::the_generated_client_calls_the_generated_service (static_assert(std::is_base_of<dds::rpc::RPCEntity, dds::rpc::Server>) and runner.run() in crates/rpc/tests/cpp/function_call_roundtrip.cpp)

Status: done — container, dispatching of requests, run() without parameter and the base RPCEntity agree. The state is in a shared object (core::Server) that copies share; rpc_runtime_roundtrip.cpp copies a Server and has the copy answer a request (31b231a9e863), and checks that a service another server holds is refused. Under the normative headers Server is the handle on core::Server (f2fc6695f1e9).

§7.11.1.5.4 Client

Spec: §7.11.1.5.4, p. 67 — “Client is a reference type and provides functions to invoke operations on a remote service synchronously and asynchronously. A Client instantiates the underlying DDS entities and makes them discoverable. Every Client inherits publicly from “interface”,“{interface}Async”, and ClientEndpoint (public virtual).”

Repo: crates/lang-rules/src/emit/interface_cpp/calls.rs::client_class (<I>Client with the bases <I>, <I>Async and public virtual dds::rpc::ClientEndpoint, operations through the requester, entities in the constructor); runtime/cpp/include/dds/rpc.hpp::Client; commit ec3707125a9b

Tests: crates/lang-rules/tests/interface_bindings.rs::cpp_binds_the_function_call_entities_of_seven_eleven_one_five, crates/rpc/tests/cpp_function_call.rs::the_generated_client_calls_the_generated_service

Status: done — copies share the entities (program crates/rpc/tests/cpp/function_call_roundtrip.cpp).

§7.11.1.5.5 ClientEndpoint

Spec: §7.11.1.5.5, p. 67 — “A ClientEndpoint provides functions to obtain the underlying DDS entities at the client side. ClientEndpoint inherits from ServiceProxy. A ClientEndpoint shall not be instantiated directly; it can be obtained from a Client object.”

Repo: runtime/cpp/include/dds/rpc.hpp::ClientEndpoint (get_request_datawriter<TReq>(), get_reply_datareader<TRep>()); commit ad892a10764a, access to the entities f8116b6debc1

Tests: crates/rpc/tests/class_summaries_are_declared.rs::the_cpp_runtime_declares_every_class_of_the_two_summaries, crates/rpc/tests/cpp_function_call.rs::the_generated_client_calls_the_generated_service (program crates/rpc/tests/cpp/function_call_roundtrip.cpp: both accessors return entities, the writer has at least one matched reader)

Status: done — inherits from ServiceProxy, protected constructor, close, wait_for_service, set_qos, qos, access to the request DataWriter and the reply DataReader.

§7.11.1.5 — Service, Server, ClientEndpoint

Spec: §7.11.1.5.1, §7.11.1.5.3, §7.11.1.5.5, p. 66–67 — as the items above.

Repo: runtime/cpp/include/dds/rpc.hpp::Server::add, Server::run, ClientEndpoint::get_request_datawriter; runtime/java/src/main/java/org/omg/dds/rpc/Server.java (run()), runtime/java/src/main/java/org/omg/dds/rpc/ClientEndpoint.java (requestWriter, replyReader); commits f8116b6debc1 (C++), 17cc6c7ad2a5 (Java)

Tests: crates/rpc/tests/cpp_function_call.rs::the_generated_client_calls_the_generated_service, crates/rpc/tests/java_rpc_runtime.rs::the_java_entities_are_interfaces_and_the_runtime_makes_services_and_clients (program crates/rpc/tests/java/RpcInheritanceTest.java: Server has run(), ClientEndpoint returns writer and reader, a bound service is refused by a second server)

Status: done — (1) Server::add (C++) refuses a service that belongs to a server (IllegalOperationError); the Java binding does so with IllegalStateException. (2) Server has run() without parameters in C++ and Java. (3) ClientEndpoint returns the request writer and the reply reader in C++ and Java.

§7.11.2 Machine-readable files for Java

Spec: §7.11.2, p. 67 — “The machine readable files associated with this specification represent the normative language bindings for Java.”

Repo: runtime/java/src/main/java/org/omg/dds/rpc/, crates/rpc/tests/java/omg-dds-rpc-java.signatures (the declarations of the zip), crates/rpc/tests/java/extract_spec_signatures.py

Tests: crates/rpc/tests/java_rpc_runtime.rs::the_java_binding_has_every_signature_of_the_machine_readable_files (SpecSignatureCheck.java), crates/rpc/tests/java_rpc_runtime.rs::the_java_entities_are_interfaces_and_the_runtime_makes_services_and_clients, crates/rpc/tests/java/RpcRuntimeRoundtrip.java::nondataSamples (…::the_java_rpc_runtime_and_the_generated_services_run_together)

Status: done — omg-dds-rpc-java.zip (from https://www.omg.org/spec/DDS-RPC/20160215/, in internal/standards/cache/omg/, not in the repository) is checked against the runtime declaration by declaration: extract_spec_signatures.py writes the 212 public declarations of the files (every type with its kind, number of type parameters and supertypes, every method with its name, static, number of type parameters, parameter and return types after erasure, the constructors, the enum constants) to omg-dds-rpc-java.signatures, and SpecSignatureCheck.java checks the compiled runtime against them by reflection. Measured on the Linux test host: 76 deviations before the change (011427669d5), 0 after it (d6674336a94). Fixed: the params without type parameters, with withDataWriterQos, withDataReaderQos, withPublisher, withSubscriber and the getters, and the generic methods simpleRequesterListener/requesterListener/simpleReplierListener/replierListener (item “§7.11.2 Java: params and DataWriter views of the PSM”); Requester.getRequestDataWriter(), getReplyDataReader(), Replier.getRequestDataReader(), getReplyDataWriter(), ClientEndpoint.getRequestDataWriter(Class), getReplyDataReader(Class), ServiceEndpoint.getRequestDataReader(Class) and getReplyDataWriter(Class) (the same item); the parameters of type org.omg.dds.core.SampleIdentity (receiveReply, waitForReplies, takeReply, takeReplies, readReply, readReplies, sendReply); Sample.Iterator is an org.omg.dds.sub.Sample.Iterator (§7.11.2.2.7: “the same as in [DDS-Java-PSM]”); the constructors RequestHeader(), ReplyHeader() and RPCRuntime(); ServiceProxy.waitForService… and waitForServices… return nothing, wait, and throw TimeoutError when the wait runs out, as the C++ binding does (isServiceMatched() asks without waiting). The return types are those of the files (f216d90e776): sendRequest returns org.omg.dds.core.SampleIdentity, sendRequestAsync and the four waitFor…Async return java.util.concurrent.Future, the operations that receive, take or read requests or replies return org.omg.dds.sub.Sample.Iterator; rpc.Sample declares no Iterator of its own, as in the file Sample.java. The objects are the runtime’s (org.omg.dds.rpc.SampleIdentity, org.omg.dds.rpc.Future with the completion listener, org.zerodds.ddsrpc.RpcSampleIterator with rpc.Sample elements). A return type that is only a subtype counts as a deviation in the test (NARROWER): code compiled against the files would not find the method, because its descriptor names the return type. Measured: 17 before the change (20241c67565), 0 after it. receiveNondataSamples(true) makes Requester and Replier hand over the samples without data (valid_data false, DDS 1.4 §2.2.2.5.1) — as a sample with validData() false, getData() null and the state of the instance —, and without the setting they do not (the default); the return value is the setting it replaces. Test: RpcRuntimeRoundtrip.java::nondataSamples over the PSM: a deleted reply writer leaves a sample without data in the state NOT_ALIVE_DISPOSED at the requester with the setting (the default WRITER_DATA_LIFECYCLE, autodispose TRUE, DDS 1.4 §2.2.3.21), nothing at the requester without it; a deleted request writer does the same at the replier. Before the change the binding did not pass such samples on, and both checks failed (20241c67565). A SimpleReplierListener is not called for a sample without data; it stays for the operations that take requests. What the runtime has beyond the files (RpcQos, ServiceMapping, ServiceMatching, WireEncoding, the binding interface org.omg.dds.rpc.DomainParticipant) the test does not check.

§7.5.1.2.6 Java: matching of endpoints by aliases and assignability

Spec: §7.5.1.2.6, p. 49 — “A client using the base interface can invoke an operation in a service that implements a derived interface as long as the same topic names are used.” And §7.7.2.5.3 and §7.7.2.5.5: changing the type of a parameter and the return type by the assignability rules.

Repo: crates/java-omgdds/java/src/main/java/org/zerodds/rtps/TypeConsistency.java, crates/java-omgdds/java/src/main/java/org/zerodds/typelookup/CompleteTypes.java, crates/java-omgdds/java/src/main/java/org/zerodds/rtps/RtpsParticipant.java (typesMatch, askTypeObject, matchAgain), crates/java-omgdds/java/src/main/java/org/zerodds/cdr/TopicTypeSupport.java::matchesByTypeInformation, runtime/java/src/main/java/org/zerodds/ddsrpc/RawTypeSupport.java, runtime/java/src/main/java/org/zerodds/ddsrpc/ZeroDdsParticipant.java::describedReaderQos, crates/lang-rules/src/emit/interface_rust/type_information.rs (minimal, JavaDescription)

Tests: crates/rpc-rust-e2e/tests/java_peer.rs::a_java_client_of_the_base_calls_a_rust_service_of_the_derived_interface, crates/rpc-rust-e2e/tests/java_peer.rs::a_rust_client_of_the_base_calls_a_java_service_of_the_derived_interface, crates/rpc-rust-e2e/tests/java_peer.rs::versions::a_changed_parameter_type_does_not_match_the_java_client, crates/rpc-rust-e2e/tests/java_peer.rs::versions::an_old_java_client_calls_an_old_rust_service, crates/rpc-rust-e2e/tests/java_peer.rs::appended_member::a_member_appended_to_a_mutable_structure_matches_the_java_client, crates/rpc-rust-e2e/tests/java_peer.rs::versions::a_return_type_the_old_one_is_not_assignable_to_does_not_match_the_java_client, crates/java-omgdds/java/src/test/java/org/zerodds/rtps/TypeConsistencyTest.java, crates/lang-rules/tests/enhanced_type_information.rs::every_minimal_identifier_the_information_announces_has_its_object

Status: done — RawTypeSupport.matchesByTypeInformation() makes the endpoints of a described topic type match by XTypes 1.3 §7.6.3.4.2: equal COMPLETE or MINIMAL identifiers, otherwise the assignability of the reader type from the writer type (§7.2.4.4) on the COMPLETE objects (TypeConsistency, CompleteTypes, TypeAssignability); without TypeInformation on one side the type names decide. RtpsParticipant.askTypeObject fetches objects of the peer with getTypes (at most three requests per identifier and peer; an object whose serialization does not hash to its identifier is not kept) and matches again after the reply (2d0f809c6e2). The Java description carries the MINIMAL objects its TypeInformation names (§7.6.3.3.4, 9b1608508c5); before, the Rust peer asked for them, got no answer and refused the pair after the TypeLookup grace. A reader of a described type announces ALLOW_TYPE_COERCION (d67a980f80b); with the default of the PSM (EXACT_TYPE, DISALLOW_TYPE_COERCION on the wire) the Rust service refused the reply reader. TypeAssignability takes two structures without members as assignable (as crates/types) and tells int8/uint8 from octet. Measured over RTPS against Rust peers (Linux test host, java_peer.rs, 8 tests): base against derived in both directions, a changed parameter type and a return type widened to long long without a match, an appended member with a match and the reply read, a control of equal versions; on 78f243b596f, before the matching by assignability, 5 of the 8 red. The other topics of the Java PSM keep matching by type name and by the TypeConsistencyEnforcement with PID 0x0072.

§7.11.2 Java: params and DataWriter views of the PSM

Spec: §7.11.2, p. 67 — “The machine readable files associated with this specification represent the normative language bindings for Java.” In omg-dds-rpc-java.zip the params carry DataWriterQos, DataReaderQos, Publisher and Subscriber of the DDS Java PSM, and Requester.getRequestDataWriter(), getReplyDataReader(), Replier.getRequestDataReader() and getReplyDataWriter() give DataWriter<TReq> and the related views.

Repo: runtime/java/src/main/java/org/omg/dds/rpc/RequesterParams.java (and ReplierParams, ServiceParams, ClientParams), runtime/java/src/main/java/org/zerodds/ddsrpc/TopicSample.java, RpcTopicTypeSupport.java, PsmEndpoint.java, RpcTopicTypes.java, ZeroDdsParticipant.java, crates/java-omgdds/java/src/main/java/org/zerodds/pub/DataWriterImpl.java::writeSerializedIdentified, crates/java-omgdds/java/src/main/java/org/zerodds/sub/DataReaderImpl.java::takeSerialized, crates/java-omgdds/java/src/main/java/org/zerodds/cdr/TypeSupportResolver.java

Tests: crates/rpc/tests/java/RpcRuntimeRoundtrip.java::psmEntities (runs in crates/rpc/tests/java_rpc_runtime.rs::the_java_rpc_runtime_and_the_generated_services_run_together), crates/rpc/tests/java/FunctionCallRoundtrip.java::run (runs in …::the_generated_function_call_client_calls_the_generated_service), crates/rpc-rust-e2e/tests/java_peer.rs (Linux test host, green)

Status: done — (d6674336a94) The params carry no type parameters any more and have withDataWriterQos, withDataReaderQos, withPublisher and withSubscriber with the getters; a DataWriterQos or DataReaderQos they name is the entity’s QoS as it stands, and the RpcQos the runtime works with is derived from it; the entities are created in the Publisher and Subscriber named (one of the participant’s, else IllegalArgumentException). ServiceParams and ClientParams pass the four settings on to their repliers and requesters, and the endpoints of the base interfaces get them through sameSettingsAs. The entities of the binding over the PSM (ZeroDdsParticipant) are DataWriter<T> and DataReader<T> of the PSM, typed by the topic type, on a Topic<T>, when the type support of the params names the class of its type (TopicSample.classOf, which every generated one does): a value written through getRequestDataWriter() is the topic’s sample as it stands, header included (TopicSample puts the header from the header member in front in the Basic mapping and reads it back there), and the runtime keeps writing and reading its own octets through the same entities (DataWriterImpl.writeSerializedIdentified, DataReaderImpl.takeSerialized with the octets kept on arrival). The type registration from a Class: TypeSupport.newTypeSupport(<I>_Request.class, …) gives the runtime’s framing through TypeSupportResolver and RpcTopicTypes instead of the reflective XCDR2 encoding. Measured (Linux test host): psmEntities makes a requester and a replier through RPCRuntime.getInstance(…), createRequesterParams().withDomainParticipant(…).withPublisher(…).withSubscriber(…).withDataWriterQos(…).withDataReaderQos(…) and createRequester(Class, Class, params); the request writer is in the Publisher and has the LIFESPAN of the DataWriterQos, the reply reader is in the Subscriber and has KEEP_LAST 11 from the DataReaderQos; the topics are typed by Calculator_Request and Calculator_Reply; a request of the runtime and its reply go through the typed entities; a request written through getRequestDataWriter() reaches the replier under the identity of its header; a reply written through getReplyDataWriter() is read through getReplyDataReader() with its value and header; a request taken through getRequestDataReader() carries the identity sendRequest returned and is gone from the replier; the type support made from the class writes the octets the requester writes, and a topic made from it carries a request with its header. FunctionCallRoundtrip.java checks the Class forms of ClientEndpoint and ServiceEndpoint for the own and the base interface and the refusal of a class that is not one. Without a typed entity the four operations return null: for a binding that is not the PSM (it refuses a Publisher, a Subscriber and a PSM QoS with RemoteUnsupportedError instead of passing over them), for a type support that names no class (such as a lambda), and when the participant already has the topic under another type. A sample the codec of the topic type cannot read is held by the typed reader without a value (getData() is null); the runtime sees its octets and answers it as §7.5.2 says. Further runs: Maven verify of the Java PSM 925 tests, 0 failures, 3 skipped; java_peer.rs 2/2 (Java client against Rust service and the other way, with the typed entities); lang-rules enhanced_java_calls, java_corpus_compiles, java_psm_mapping, type_pair_java 28 passed, 2 ignored (the full corpus runs, as before).

§7.11.2 Type mapping by DDS-Java-PSM

Spec: §7.11.2, p. 67 — “The Java language binding shall use IDL type mapping as per [DDS-Java-PSM].”

Repo: crates/lang-rules/src/adapter/java.rs::java_member_type (mapping per DDS-Java-PSM Clause 9, selectable with idlc generate --lang java --java-mapping psm); crates/lang-rules/src/emit/interface_java.rs; commit 5e078003c162, interfaces 1214333fd89f

Tests: crates/lang-rules/tests/java_psm_mapping.rs::an_aggregate_is_a_final_class_with_private_state_and_bean_accessors, crates/lang-rules/tests/java_psm_mapping.rs::an_unbounded_sequence_is_a_collection_and_a_bounded_one_an_array, crates/lang-rules/tests/java_psm_mapping.rs::an_interface_is_generated_under_the_psm_mapping, crates/lang-rules/tests/interface_bindings.rs::java_declares_the_same_entities_as_cpp

Status: done — data types and the types of an interface (request, reply, parameters, services) can be mapped per Clause 9 (item below).

§7.11.2 Type mapping of interfaces under DDS-Java-PSM Clause 9

Spec: §7.11.2, p. 67 — as above.

Repo: crates/lang-rules/src/emit/interface_java.rs (java_interface_items takes --java-mapping psm; the holders Request, Reply, In, Out, Result keep public fields and take the types of the mapping, the codec reaches the data types through accessors); commit 1214333fd89f

Tests: crates/lang-rules/tests/java_psm_mapping.rs::an_interface_is_generated_under_the_psm_mapping, crates/lang-rules/tests/java_psm_mapping.rs::an_interface_under_the_psm_mapping_compiles, crates/lang-rules/tests/java_psm_mapping.rs::a_type_pair_under_the_psm_mapping_compiles

Status: done — Basic and Enhanced; the generated sources compile with -Xlint:all -Werror. Like the data types, the services are in the outer class ZdServices (interface_java.rs::OUTER), the same under both mappings.

§7.11.2 Differences from the C++ binding

Spec: §7.11.2, p. 67 — “The following sub clauses describe the entities that are either different or not described in the C++ language bindings.”

Repo: —

Tests: —

Status: n/a (informative) — introduction.

§7.11.2.1 Mapping of Exceptions

Spec: §7.11.2.1, p. 67 — heading without text.

Repo: —

Tests: —

Status: n/a (informative) — the section has no content. The Java runtime has five Remote*Error classes over RuntimeException (runtime/java/src/main/java/org/omg/dds/rpc/).

§7.11.2.2.1 Packages org.omg.dds and org.omg.dds.rpc

Spec: §7.11.2.2.1, p. 67 — “The org.omg.dds, and org.omg.dds.rpc packages define the interfaces for the request-reply style language binding. Specifically, the language binding includes Requester, Replier, ServiceProxy, RPCEntity, RPCRuntime, SimpleReplierListener, ReplierListener, SimpleRequesterListener, RequesterListener, RequesterParams, ReplierParams, Future, FutureCompletionListener, Sample, and Sample.Iterator.”

Repo: runtime/java/src/main/java/org/omg/dds/rpc/; crates/rpc/src/language_binding.rs (JAVA_PACKAGES, JAVA_REQUEST_REPLY_TYPES); commit 771f12846807

Tests: crates/rpc/tests/class_summaries_are_declared.rs::the_java_package_declares_every_type_of_the_two_summaries

Status: done — all 15 types exist; Sample.Iterator is nested in Sample.java. The interface form is in the item below.

§7.11.2.2.1 Types as interfaces

Spec: §7.11.2.2.1 and §7.11.2.2.3, p. 67 — “define the interfaces”; “RPCRuntime is the only abstract class with placeholder implementation in the Java language binding.”

Repo: runtime/java/src/main/java/org/omg/dds/rpc/ (Requester, Replier, RequesterParams, ReplierParams, Server are interfaces; implementations RequesterImpl, ReplierImpl, RequesterParamsImpl, ReplierParamsImpl, ServerImpl; RPCRuntime is the abstract class); commit 771f12846807

Tests: crates/rpc/tests/java_rpc_runtime.rs::the_java_rpc_runtime_and_the_generated_services_run_together (the program compiles RequesterImpl implements Requester and the other implementations)

Status: done

§7.11.2.2.2 RPCEntity

Spec: §7.11.2.2.2, p. 67 — “RPCEntity is the base interface extended by all the active entities. It inherits from the DDSObject interface defined in [DDS-Java-PSM] and java.io.Closeable. Its purpose is to provide quick access to the RPCRuntime object.”

Repo: runtime/java/src/main/java/org/omg/dds/rpc/RPCEntity.java; runtime/java/src/main/java/org/omg/dds/rpc/Server.java (extends RPCEntity, Runnable); commit 8853bea2e973, access to the runtime 771f12846807, getRPCRuntime 25d188119b45, Server 17cc6c7ad2a5

Tests: crates/java-omgdds/java/src/test/java/org/omg/dds/rpc/RpcInheritanceTest.java::rpcEntityInheritsDdsObjectAndCloseable, crates/java-omgdds/java/src/test/java/org/omg/dds/rpc/RpcInheritanceTest.java::anEntityAnRpcRuntimeMadeReturnsThatRuntime, crates/rpc/tests/java_rpc_runtime.rs::the_java_entities_are_interfaces_and_the_runtime_makes_services_and_clients (program crates/rpc/tests/java/RpcInheritanceTest.java: Server extends RPCEntity)

Status: done — inheritance, access to the runtime and Server as an RPCEntity.

§7.11.2.2.3 RPCRuntime: abstract class over ServiceEnvironment

Spec: §7.11.2.2.3, p. 67 — “RPCRuntime is the only abstract class with placeholder implementation in the Java language binding. It extends ServiceEnvironment abstract class defined in [DDS-Java-PSM].”

Repo: runtime/java/src/main/java/org/omg/dds/rpc/RPCRuntime.java; commit 771f12846807

Tests: crates/java-omgdds/java/src/test/java/org/omg/dds/rpc/RpcInheritanceTest.java::aServiceEnvironmentReturnsItself, crates/rpc/tests/java_rpc_runtime.rs::the_java_rpc_runtime_and_the_generated_services_run_together

Status: done

§7.11.2.2.3 RPCRuntime as singleton and factory of all entities

Spec: §7.11.2.2.3, p. 67 — “Its purpose is to provide access to the RPCRuntime singleton, which serves as a factory for all other entities.”

Repo: runtime/java/src/main/java/org/omg/dds/rpc/RPCRuntime.java (over, createRequester, createReplier, createServer, createRequesterParams, createReplierParams, createServiceParams, createClientParams, createService, createClient, release); commit 771f12846807, service and client 17cc6c7ad2a5

Tests: crates/rpc/tests/java_rpc_runtime.rs::the_java_rpc_runtime_and_the_generated_services_run_together (program crates/rpc/tests/java/RpcRuntimeRoundtrip.java: over() returns the one runtime of a participant), crates/rpc/tests/java_rpc_runtime.rs::the_java_entities_are_interfaces_and_the_runtime_makes_services_and_clients (program crates/rpc/tests/java/RpcInheritanceTest.java: createService and createClient return entities of the runtime)

Status: done — over(participant) returns the same instance per participant; factories for Requester, Replier, Server, Service, Client and the params.

§7.11.2.2.3 RPCRuntime factory for Service and Client

Spec: §7.11.2.2.3, p. 67 — as above.

Repo: runtime/java/src/main/java/org/omg/dds/rpc/RPCRuntime.java::createService, RPCRuntime.java::createClient (take the constructor of the generated <I>ServiceImpl or <I>ClientImpl, also with an instance name); ServiceParams, ClientParams; commit 17cc6c7ad2a5

Tests: crates/rpc/tests/java_rpc_runtime.rs::the_java_entities_are_interfaces_and_the_runtime_makes_services_and_clients (program crates/rpc/tests/java/RpcInheritanceTest.java: service.getEnvironment() == runtime, a call of the client reaches the service, instance name bound, createService without a participant is refused)

Status: done

§7.11.2.2.4 Future

Spec: §7.11.2.2.4, p. 67 — “The rpc.Future interface extends the java.util.concurrent.Future interface and adds a single operation to specify a FutureCompletionListener.”

Repo: runtime/java/src/main/java/org/omg/dds/rpc/Future.java (setListener); commit ad892a10764a

Tests: crates/rpc/tests/java_rpc_runtime.rs::the_java_rpc_runtime_and_the_generated_services_run_together

Status: done

§7.11.2.2.5 FutureCompletionListener

Spec: §7.11.2.2.5, p. 68 — “The FutureCompletionListener allows callback notification when the corresponding future becomes ready.”

Repo: runtime/java/src/main/java/org/omg/dds/rpc/FutureCompletionListener.java (onFutureComplete); commit ad892a10764a

Tests: crates/rpc/tests/java_rpc_runtime.rs::the_java_rpc_runtime_and_the_generated_services_run_together

Status: done

§7.11.2.2.6 Sample

Spec: §7.11.2.2.6, p. 68 — “The rpc.Sample interface extends dds.sub.Sample interface and defines two additional operations to retrieve the SampleIdentity and the related sample identity, if any.”

Repo: runtime/java/src/main/java/org/omg/dds/rpc/Sample.java (identity, relatedIdentity); commit 771f12846807

Tests: crates/java-omgdds/java/src/test/java/org/omg/dds/rpc/RpcInheritanceTest.java::rpcSampleExtendsThePsmSampleOverTheSameParameter, crates/java-omgdds/java/src/test/java/org/omg/dds/rpc/RpcInheritanceTest.java::anRpcSampleIsAPsmSample

Status: done — the interface additionally declares validData().

§7.11.2.2.7 Sample.Iterator as in DDS-Java-PSM

Spec: §7.11.2.2.7, p. 68 — “The Sample.Iterator interface is the same as in [DDS-Java-PSM].” DDS-Java-PSM §7.7.2 (p. 16 of the PDF dds-java-psm-1.0.pdf): “an iterator that extends java.util.ListIterator”; page 17: “the iterator implements the Java.io.Closeable interface”.

Repo: runtime/java/src/main/java/org/omg/dds/rpc/Sample.java (Sample.Iterator extends java.io.Closeable, java.util.ListIterator<Sample<T>>, Sample.iterate; remove, set and add throw UnsupportedOperationException); commit 771f12846807, Closeable 17cc6c7ad2a5

Tests: crates/rpc/tests/java_rpc_runtime.rs::the_java_rpc_runtime_and_the_generated_services_run_together (program crates/rpc/tests/java/RpcRuntimeRoundtrip.java: instanceof java.util.ListIterator, backward walk, remove refused), crates/rpc/tests/java_rpc_runtime.rs::the_java_entities_are_interfaces_and_the_runtime_makes_services_and_clients (program crates/rpc/tests/java/RpcInheritanceTest.java: Closeable, close() without a checked exception, next() after close(), try-with-resources)

Status: done — ListIterator, read-only access and java.io.Closeable match.

§7.11.2.2.7 Sample.Iterator: Closeable and returnLoan

Spec: §7.11.2.2.7, p. 68 — as above.

Repo: runtime/java/src/main/java/org/omg/dds/rpc/Sample.java::Sample.Iterator (close, returnLoan, isClosed); commit 17cc6c7ad2a5

Tests: crates/rpc/tests/java_rpc_runtime.rs::the_java_entities_are_interfaces_and_the_runtime_makes_services_and_clients (program crates/rpc/tests/java/RpcInheritanceTest.java: Closeable is a supertype, close() ends the walk, a second close() is allowed, leaving try-with-resources returns the loan)

Status: done

§7.11.2.3 Function-call in Java with the entities of C++

Spec: §7.11.2.3, p. 68 — “Function-Call style language binding in Java shall define the same entities as that of C++.”

Repo: runtime/java/src/main/java/org/omg/dds/rpc/ (Service, ServiceEndpoint, Server, Client, ClientEndpoint, FunctionCallService, FunctionCallClient); crates/lang-rules/src/emit/interface_java.rs (client_interface, service_interface); crates/lang-rules/src/emit/interface_java/calls.rs (client_class, service_class); commit c512ee365514, Server, ClientEndpoint and runtime 17cc6c7ad2a5

Tests: crates/rpc/src/language_binding.rs::tests::the_java_function_call_types_are_the_cpp_ones, crates/lang-rules/tests/interface_bindings.rs::java_declares_the_same_entities_as_cpp, crates/rpc/tests/java_rpc_runtime.rs::the_generated_function_call_client_calls_the_generated_service, crates/rpc/tests/java_rpc_runtime.rs::the_java_entities_are_interfaces_and_the_runtime_makes_services_and_clients

Status: done — the five entities are declared and implemented; Server ties a Service to exactly one server (IllegalStateException), has run() and is an RPCEntity; ClientEndpoint returns the request writer and the reply reader.


Audit-Status

371 done / 0 partial / 0 open / 0 blocked / 44 n/a (informative).

Open items: none.


  1. [:alnum:]_ ↩︎

DDS-RPC 1.0 — Spec-Coverage

Quelle: internal/standards/cache/omg/dds-rpc-1.0.pdf (68 Seiten, OMG formal/2017-04-01) — OMG DDS-RPC 1.0

Audit Item für Item gegen die PDF nach internal/spec-coverage/PROCESS.md. Seitenangaben sind PDF-Seiten (PDF-Seite = gedruckte Seite + 4). Jede Regel der Abbildung auf Topics und Typen, jede Annotation, jedes Feld der Erweiterungen der Discovery, jede Regel der Evolution, jeder Schritt der Korrelation und jede Klasse der Sprachbindungen ist ein eigenes Item. done steht nur, wo Code und Test die Anforderung abdecken; ein zitierter Test nennt die Testfunktion als datei::modul::name. Eine Fundstelle im Repo nennt Datei und Symbol; die Commits, die eine Anforderung erfüllt haben, stehen mit ihrem 12-stelligen Hash beim Item. Jede Aussage über Verhalten ist aus dem Code gelesen. Auf dem Mac wurde nichts ausgeführt (dort wird nur kompiliert). Die Tests liefen auf einem Linux-Testhost in den Runden 1 bis 10; die Runde 10 war ohne Fehler (Quelle: Ergebnisse der Testläufe des Maintainers, nicht Teil dieser Datei).

Kontext: DDS-RPC ist in ZeroDDS über diese Teile verteilt:

  • crates/rpc/ · docs.rs — Laufzeit in Rust (Requester, Replier, wire_codec), Datenmodell der Abbildung (service_mapping, codegen, enhanced), Namen der Topics (topic_naming), Annotationen (annotations), gemeinsame Typen (common_types), Paar von Typen mit eigenem header (type_pair, header_pair), Function-call (function_call), Leser für Dienstdefinitionen in Java (java_service_def), Tabellen der Sprachbindungen (language_binding), QoS (qos_profile), Daten der Discovery (discovery_ext, endpoint), Tabelle der Evolution (evolution_rules).
  • crates/lang-rules/src/adapter/interface.rs · docs.rs — Leser eines IDL-interface für die Generatoren; crates/lang-rules/src/emit/interface_cpp.rs mit interface_cpp/, interface_java.rs mit interface_java/ und interface_rust.rs mit interface_rust/ — erzeugter Code für C++, Java und Rust (Basic und Enhanced, Function-call und Paar von Typen).
  • runtime/cpp/include/dds/rpc.hpp — Laufzeit der C++-Bindung; runtime/cpp/include/dds/rpc/zerodds.hpp — ihre Anbindung an die C-API von ZeroDDS.
  • runtime/java/src/main/java/org/omg/dds/rpc/ (die Schnittstellen der Spec) und runtime/java/src/main/java/org/zerodds/ddsrpc/ (die Implementierungen RequesterImpl, ReplierImpl, ServerImpl) — Laufzeit der Java-Bindung. runtime/java/src/main/java/org/zerodds/ddsrpc/ (ZeroDdsParticipant, RawTypeSupport) bindet sie an die DDS-Java-PSM-Implementierung in crates/java-omgdds/, einschließlich PID_RELATED_SAMPLE_IDENTITY (Merge a2a9a67acb58). Die Tests der Laufzeit benutzen zusätzlich eine Schleife im Speicher (crates/rpc/tests/java/RpcRuntimeRoundtrip.java).
  • crates/rtps/ · docs.rs — Parameter-IDs 0x0080 bis 0x0083 und ihre Codecs; crates/dcps/src/runtime.rs — Senden und Empfangen von PID_RELATED_SAMPLE_IDENTITY und der Erweiterungen der Discovery.
  • crates/zerodds-c-api/ · docs.rs — Funktionen für RPC: zerodds_writer_write_related, zerodds_reader_take_wire, rpc_discovery_ffi.rs, rpc_profile_ffi.rs, rpc_qos_ffi.rs; das Feature rpc schaltet rpc_discovery_ffi.rs und rpc_profile_ffi.rs.
  • crates/rpc-rust-e2e/ — erzeugte Rust-Bindung über einer echten DcpsRuntime auf Loopback.

Die Spec definiert Sprachbindungen für C++ und Java (§7.11). Die Rust-API in crates/rpc/ und die erzeugte Rust-Bindung sind keine Bindung der Spec; sie sind als Fundstelle genannt, wo sie das Verhalten tragen, das eine Regel verlangt. Wo sich die Laufzeiten für Rust, C++ und Java unterscheiden, sagt das Item es. Weitere Sprachen der Generatoren (C#, Go, TypeScript u. a.) regelt die Spec nicht; sie sind nicht als Items geführt. Eine C-Bindung kennt die Spec nicht; die C-API von ZeroDDS trägt die Funktionen, auf denen die C++-Bindung aufsetzt (siehe oben), und ist selbst keine Bindung der Spec.

Die Spec nennt drei maschinenlesbare Dateien als normativ (omg-dds-rpc-cxx.zip, omg-dds-rpc-java.zip, omg-dds-rpc-idl.zip, S. 1). Sie liegen in internal/standards/cache/omg/ und sind abgeglichen: die C++-Header liegen unverändert in runtime/cpp/include/dds/rpc/normative/ (Item zu §7.11.1), die Java-Dateien Signatur für Signatur gegen die Java-Laufzeit (SpecSignatureCheck, Item zu §7.11.2), robot.idl gegen die Namen der Generatoren (crates/lang-rules/tests/rpc_idl_zip_agrees.rs).

Offene Punkte: keine; jedes Item ist done oder n/a (informative).


§1 Scope

§1 Scope

Spec: §1, S. 13 — “This specification defines a Remote Procedure Calls (RPC) framework using the basic building blocks of DDS, such as topics, types, DataReaders, and DataWriters to provide request/reply semantics. […] It supports synchronous and asynchronous method invocation.”

Repo: —

Tests: —

Status: n/a (informative) — Übersicht; die Bausteine und die Arten des Aufrufs sind in §7 einzeln geführt.


§2 Conformance

§2 Konformitätspunkte Basic und Enhanced

Spec: §2, S. 13 — “This specification defines two conformance points: Basic and Enhanced. [1] Basic conformance (mandatory) [2] Enhanced conformance (optional)”.

Repo: —

Tests: —

Status: n/a (informative) — Zuordnung; ob ein Punkt erfüllt ist, folgt aus dem Status der zugeordneten Items.

§2 Basic conformance — Zuordnung

Spec: §2, S. 13 — “The basic conformance point includes support for the Basic service mapping and both the functional and the request-reply language binding styles.”

Repo: —

Tests: —

Status: n/a (informative) — Zuordnung; die Basic-Abbildung steht in §7.4.2, §7.5.1.1, §7.6.1, §7.7.1 und §7.8.1, die beiden Stile in §7.2.2 und §7.11.

§2 Enhanced conformance — Zuordnung

Spec: §2, S. 13 — “The enhanced conformance point includes the basic conformance and adds support for the Enhanced Service mapping.”

Repo: —

Tests: —

Status: n/a (informative) — Zuordnung; die Enhanced-Abbildung steht in §7.4.3, §7.5.1.2, §7.6.2, §7.7.2 und §7.8.2.


§3 Normative References

§3 Normative References

Spec: §3, S. 13–14 — [DDS] 1.2, [RTPS], [DDS-Xtypes] 1.0 Beta 1, [CORBA] 3.3, [IDL35], [EBNF], [Java-Grammar], [DDS-Cxx-PSM], [DDS-Java-PSM], [DDS4CCM], [IDL2Java], [SOA-RM].

Repo: —

Tests: —

Status: n/a (informative) — Literaturliste; wo eine referenzierte Norm eine Anforderung trägt (Grammatik von IDL und Java, DDS-Cxx-PSM, DDS-Java-PSM, DDS4CCM), steht sie beim Item, das sie verwendet.


§4 Terms and Definitions

§4 Service, Remote Procedure Call

Spec: §4, S. 14 — Definitionen von “Service” (nach [SOA-RM]) und “Remote Procedure Call”.

Repo: —

Tests: —

Status: n/a (informative) — Begriffe.


§5 Symbols and Abbreviated Terms

§5 Abkürzungen

Spec: §5, S. 14 — DDS, GUID, RPC, RTPS, SN.

Repo: —

Tests: —

Status: n/a (informative) — Abkürzungen.


§6 Additional Information

§6.1 Acknowledgements

Spec: §6.1, S. 15 — einreichende und unterstützende Firmen.

Repo: —

Tests: —

Status: n/a (informative) — Danksagung.


§7.1 Overview

§7.1 Overview

Spec: §7.1, S. 17 — “The intent of this specification is to specify higher-level abstractions built on top of DDS to achieve first-class request/reply communication.”

Repo: —

Tests: —

Status: n/a (informative) — Absicht der Spec.


§7.2 General Concepts

§7.2.1 Client: DataWriter für Requests, DataReader für Replies

Spec: §7.2.1, S. 17 — “Structurally, every client uses a data writer for sending requests and a data reader for receiving replies.”

Repo: crates/rpc/src/requester.rs (Requester, Felder request_writer und reply_reader, angelegt in Requester::from_topics); runtime/cpp/include/dds/rpc.hpp (Requester); runtime/java/src/main/java/org/omg/dds/rpc/Requester.java (Interface), RequesterImpl.java

Tests: crates/rpc/tests/runtime_e2e.rs::e2e_single_request_response_roundtrip, crates/rpc-rust-e2e/tests/e2e.rs::the_generated_calculator_binding_runs_every_call, crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together, crates/rpc/tests/java_rpc_runtime.rs::the_java_rpc_runtime_and_the_generated_services_run_together

Status: done — alle drei Laufzeiten halten je einen Writer für Requests und einen Reader für Replies. Die Java-Laufzeit als Interfaces: 771f12846807.

§7.2.1 Service: DataReader für Requests, DataWriter für Replies

Spec: §7.2.1, S. 17 — “Symmetrically, every service uses a data reader for receiving the requests and a data writer for sending the replies.”

Repo: crates/rpc/src/replier.rs (Replier, Felder request_reader und reply_writer, angelegt in Replier::from_topics); runtime/cpp/include/dds/rpc.hpp (Replier); runtime/java/src/main/java/org/omg/dds/rpc/Replier.java (Interface), ReplierImpl.java

Tests: crates/rpc/src/replier.rs::tests::tick_processes_request_and_writes_reply, crates/rpc-rust-e2e/tests/e2e.rs::the_generated_calculator_binding_runs_every_call, crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together, crates/rpc/tests/java_rpc_runtime.rs::the_java_rpc_runtime_and_the_generated_services_run_together

Status: done — alle drei Laufzeiten halten je einen Reader für Requests und einen Writer für Replies. Die Java-Laufzeit als Interfaces: 771f12846807.

§7.2.1 Replies anderer Clients werden ausgefiltert

Spec: §7.2.1, S. 17 — “To ensure that the client receives a response to a previous call made by itself, a content-based filter is used by the reader at the client-side. This ensures that responses for remote invocations of other clients are filtered.”

Repo: crates/rpc/src/requester.rs::Requester::tick (ein Reply, dessen related_request_id keinem offenen Request entspricht, wird verworfen); runtime/cpp/include/dds/rpc.hpp (Requester, decode_reply und decode_enhanced_reply: Vergleich der GUID in related_request_id mit der GUID des eigenen Request-Writers request_writer_guid_); runtime/java/src/main/java/org/zerodds/ddsrpc/RequesterImpl.java (drain: derselbe Vergleich mit requestWriterGuid)

Tests: crates/rpc/src/requester.rs::tests::tick_drops_reply_without_matching_request, crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together (Abschnitt “a reply to another client is filtered out” in crates/rpc/tests/cpp/rpc_runtime_roundtrip.cpp), crates/rpc/tests/java_rpc_runtime.rs::the_java_rpc_runtime_and_the_generated_services_run_together (derselbe Abschnitt in crates/rpc/tests/java/RpcRuntimeRoundtrip.java)

Status: done — alle drei Laufzeiten reichen keinen Reply an die Anwendung, der zu einem Request eines anderen Clients gehört. Der Filter arbeitet im Requester nach dem Lesen, nicht als ContentFilteredTopic des DataReaders; die Spec verlangt die Wirkung. C++ und Java: 35aa702e4900.

§7.2.1 Filter nach Inhalt in C++ und Java

Spec: §7.2.1, S. 17 — wie oben.

Repo: runtime/cpp/include/dds/rpc.hpp (Requester, request_writer_guid_); runtime/java/src/main/java/org/zerodds/ddsrpc/RequesterImpl.java (requestWriterGuid, drain)

Tests: crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together, crates/rpc/tests/java_rpc_runtime.rs::the_java_rpc_runtime_and_the_generated_services_run_together

Status: done — Requester::receive_replies (C++) und drain (Java) verwerfen einen Reply, dessen related_request_id die GUID eines anderen Request-Writers trägt, bevor er an die Anwendung oder an ihre Fehlerbehandlung geht. Im Enhanced-Pfad gilt derselbe Vergleich für die related_identity aus PID_RELATED_SAMPLE_IDENTITY. 35aa702e4900.

§7.2.1 Mehrere offene Requests eines Clients

Spec: §7.2.1, S. 17 — “It is possible for a client to have more than one outstanding request […] As a consequence, each individual request must be correlated with the corresponding reply.”

Repo: crates/rpc/src/requester.rs (Requester::pending, Zuordnung in Requester::tick); runtime/cpp/include/dds/rpc.hpp (Requester::pending_, Requester::receive_reply); runtime/java/src/main/java/org/zerodds/ddsrpc/RequesterImpl.java (receiveReply(SampleIdentity))

Tests: crates/rpc/tests/runtime_e2e.rs::e2e_multi_pending_requests_all_get_their_reply, crates/rpc/src/requester.rs::tests::tick_correlates_reply_with_pending_slot, crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together (Abschnitt “two outstanding requests”), crates/rpc/tests/java_rpc_runtime.rs::the_java_rpc_runtime_and_the_generated_services_run_together (derselbe Abschnitt)

Status: done — Zuordnung über die SampleIdentity des Requests in allen drei Laufzeiten; ein Reply wird dem Request zugeordnet, auch wenn die Replies in anderer Reihenfolge eintreffen.

§7.2.1 Ein Request ist durch seine SampleIdentity identifiziert

Spec: §7.2.1, S. 17 — “Requests, like all samples in the DDS data space, are identified using a unique SampleIdentity defined as a struct composed of GUID_t and a SequenceNumber_t defined in sub clause 7.5.1.1.1 Common Types.”

Repo: crates/rpc/src/common_types.rs::SampleIdentity; crates/rpc/src/requester.rs::Requester::next_request_id; runtime/cpp/include/dds/rpc.hpp (dds::SampleIdentity); runtime/java/src/main/java/org/omg/dds/rpc/SampleIdentity.java

Tests: crates/rpc/src/requester.rs::tests::send_request_async_assigns_unique_sample_ids, crates/rpc/src/common_types.rs::tests::sample_identity_invalid_constant_is_rtps_unknown

Status: done — der Typ besteht aus GUID und SequenceNumber_t in allen drei Laufzeiten, und jeder Request erhält eine eindeutige Identität. Dass diese Identität die des Samples ist, steht im folgenden Item.

§7.2.1 Identität des Requests ist die des Samples

Spec: §7.2.1, S. 17 — wie oben.

Repo: Rust: crates/rpc/src/requester.rs::Requester::next_request_id (GUID des Request-Writers und DataWriter::next_sequence_number, aufgerufen unter send_lock); crates/dcps/src/publisher.rs (DataWriter::next_sequence_number). Java: runtime/java/src/main/java/org/zerodds/ddsrpc/ZeroDdsParticipant.java (nextIdentity fragt psm.nextIdentity() des Writers in crates/java-omgdds/java/src/main/java/org/zerodds/pub/DataWriterImpl.java). C++: runtime/cpp/include/dds/rpc/zerodds.hpp (Writer::next_identity fragt zerodds_writer_next_sequence_number in crates/zerodds-c-api/src/lib.rs)

Tests: crates/rpc-rust-e2e/tests/e2e.rs::a_live_request_identity_is_the_rtps_identity_of_the_request_writer, crates/java-omgdds/java/src/test/java/org/omg/dds/rpc/ZeroDdsParticipantTest.java::aWriteReturnsItsIdentityAndTheReaderSeesItWithTheRelatedOne, crates/zerodds-c-api/tests/writer_next_sequence_number.rs::the_next_sequence_number_is_the_one_the_next_write_carries

Status: done — Rust und Java tragen die Identität des Samples im RequestHeader (Rust 2314c1c5fb58, Java über die PSM-Bindung a2a9a67acb58). In C++ liefert Writer::next_identity die Folgenummer vom Writer über zerodds_writer_next_sequence_number (94181922bf32). Das Programm crates/rpc/tests/cpp/real_library_roundtrip.cpp lässt die C++-Anbindung (runtime/cpp/include/dds/rpc/zerodds.hpp) gegen die echte C-Bibliothek libzerodds laufen: zwei Runtimes einer Domain, erzeugter Client und Service der Enhanced-Abbildung, jeder Aufruf wird über die Identität des Samples und PID_RELATED_SAMPLE_IDENTITY dem Reply zugeordnet (Test crates/rpc/tests/cpp_rpc_real_library.rs::the_cpp_binding_runs_against_libzerodds, Commit 192200b5a2e1; auf dem Linux-Testhost gelaufen, grün). Der Lauf fand einen Fehler, behoben in 90be3edf2d76: ClientEndpoint::bind band die Requester, über die der Client sendet, nicht an die Instanz.

§7.2.1 Der Reply nennt die Identität des Requests

Spec: §7.2.1, S. 17 — “When a service implementation sends a reply to a specific remote invocation, it is necessary to identify the original request by providing the sample-identity of the request.”

Repo: crates/rpc/src/replier.rs::Replier::tick (ReplyHeader::new mit header.request_id; Enhanced: write_related); runtime/cpp/include/dds/rpc.hpp (Replier::send_reply mit related_request_id); runtime/java/src/main/java/org/omg/dds/rpc/Replier.java (sendReply(reply, relatedRequestId))

Tests: crates/rpc/src/replier.rs::tests::tick_processes_request_and_writes_reply, crates/rpc/tests/runtime_e2e.rs::e2e_client_side_request_identity_is_the_one_the_reply_relates_to, crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together (Prüfung “related_request_id is the request’s identity”)

Status: done — Rust, C++ und Java schreiben die Identität des Requests in den Reply (Basic: ReplyHeader::related_request_id; Enhanced: PID_RELATED_SAMPLE_IDENTITY). C++ und Java: 58634aa2702a; Enhanced: e305669e2c42, C++ 2bfb2786121b.

§7.2.1 Eigene Identität des Replys

Spec: §7.2.1, S. 17 — “Note that a reply data sample has its own unique message-id (sample identity), which represents the reply message itself and is independent of the request sample-identity.”

Repo: —

Tests: —

Status: n/a (informative) — Hinweis auf eine Eigenschaft jedes DDS-Samples.

§7.2.2 Zwei Stile der Sprachbindung

Spec: §7.2.2, S. 18 — “This specification includes a higher-level language binding with function-call style and a lower-level language binding with request/reply style.”

Repo: —

Tests: —

Status: n/a (informative) — Übersicht; die Pflicht steht in §7.2.2.3.

§7.2.2.1 Function-call Style

Spec: §7.2.2.1, S. 18 — “To provide function-call style, a common approach is to generate stubs that serve as client-side proxies for remote operations and skeletons to support service-side implementations.”

Repo: —

Tests: —

Status: n/a (informative) — Beschreibung; die Entitäten stehen in §7.11.1.5 und §7.11.2.3.

§7.2.2.2 Request/Reply Style

Spec: §7.2.2.2, S. 18 — “The request/reply style provides a flat interface, such as send_request, receive_request, and send_reply, receive_reply”.

Repo: —

Tests: —

Status: n/a (informative) — Beschreibung; die Operationen stehen in §7.11.1.4 und §7.11.2.2.

§7.2.2.3 Vor- und Nachteile der Stile

Spec: §7.2.2.3, S. 19 — Vergleich der Stile; “It is possible for a client to use function-call style language binding to invoke remote operations on a server that uses request/reply style language binding to implement the service.”

Repo: crates/rpc/src/topic_naming.rs (BindingStyle, ServiceTopicNames: der Stil Request/Reply nimmt den Namen des Interface nicht auf, §7.4.1); crates/rpc/src/requester.rs, crates/rpc/src/replier.rs (with_instance_style, with_topics_style, with_options)

Tests: crates/rpc/src/requester.rs::tests::request_reply_style_drops_the_interface_segment, crates/rpc/tests/language_binding_agreement.rs::both_readings_of_seven_four_produce_the_same_topic_names, crates/rpc-rust-e2e/tests/e2e.rs::the_generated_calculator_binding_runs_every_call (ein Requester im Stil Request/Reply ruft den erzeugten Service im Stil Function-call auf), crates/rpc/tests/cpp_function_call.rs::the_generated_client_calls_the_generated_service, crates/rpc/tests/java_rpc_runtime.rs::the_generated_function_call_client_calls_the_generated_service (dieselbe Richtung in C++ und Java), crates/rpc-rust-e2e/tests/evolution_styles_discovery.rs::a_basic_function_call_client_calls_a_request_reply_service (erzeugter Client im Stil Function-call gegen einen Replier im Stil Request/Reply)

Status: done — die Namen der Topics folgen §7.4.1 für beide Stile (6834e51fdfef), die Entitäten im Stil Request/Reply sprechen mit dem erzeugten Service im Stil Function-call, und der erzeugte Client im Stil Function-call (CalculatorClient) ruft einen Replier mit BindingStyle::RequestReply auf gleich gesetzten Namen der Topics auf (414e077c527d). Der Test prüft die Namen demo_Calculator_Service_Request und demo_Calculator_Service_Reply und zwei Aufrufe von add.

§7.2.2.3 Beide Stile werden unterstützt

Spec: §7.2.2.3, S. 19 — “In light of the above observation, a conforming implementation to this specification shall support both styles of language binding.”

Repo: Rust: crates/rpc/src/requester.rs, crates/rpc/src/replier.rs (Request/Reply), crates/lang-rules/src/emit/interface_rust.rs (client_impl, dispatcher_impl; Function-call). C++: runtime/cpp/include/dds/rpc.hpp (Requester, Replier), crates/lang-rules/src/emit/interface_cpp/calls.rs (client_class, service_class). Java: runtime/java/src/main/java/org/omg/dds/rpc/ (RequesterImpl, ReplierImpl, FunctionCallClient, FunctionCallService), crates/lang-rules/src/emit/interface_java/calls.rs (client_class, service_class)

Tests: crates/rpc/tests/runtime_e2e.rs::e2e_single_request_response_roundtrip, crates/rpc-rust-e2e/tests/e2e.rs::the_generated_calculator_binding_runs_every_call, crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together, crates/rpc/tests/cpp_function_call.rs::the_generated_client_calls_the_generated_service, crates/rpc/tests/java_rpc_runtime.rs::the_java_rpc_runtime_and_the_generated_services_run_together, crates/rpc/tests/java_rpc_runtime.rs::the_generated_function_call_client_calls_the_generated_service

Status: done — beide Stile laufen in Rust, C++ und Java. C++ Function-call ec3707125a9b, Java Function-call c512ee365514.

§7.2.2.3 Function-call in C++ und Java

Spec: §7.2.2.3, S. 19 — wie oben.

Repo: crates/lang-rules/src/emit/interface_cpp/calls.rs (client_class, service_class; <I>Client leitet von dds::rpc::ClientEndpoint ab, <I>Service von dds::rpc::Service, das dds::rpc::Server::add annimmt); runtime/cpp/include/dds/rpc.hpp (Service, Server); crates/lang-rules/src/emit/interface_java/calls.rs (client_class, service_class: <I>ClientImpl, <I>ServiceImpl); runtime/java/src/main/java/org/omg/dds/rpc/FunctionCallClient.java, FunctionCallService.java

Tests: crates/rpc/tests/cpp_function_call.rs::the_generated_client_calls_the_generated_service, crates/rpc/tests/cpp_enhanced_function_call.rs::the_generated_enhanced_client_calls_the_generated_enhanced_service, crates/rpc/tests/java_rpc_runtime.rs::the_generated_function_call_client_calls_the_generated_service

Status: done — der erzeugte Client ruft über einen Requester, der erzeugte Service antwortet über einen Replier; in C++ nimmt Server::add den Service an. C++: ec3707125a9b, Java: c512ee365514, Enhanced in C++ 45ead22cc2b9 und in Java 2ea77f7dad8a.

§7.2.3 Identität an Requester und Service abrufbar

Spec: §7.2.3, S. 19 — “Request-reply correlation requires an ability to retrieve the sample identity (GUID, SN) at both the requester and service side.”

Repo: crates/rpc/src/requester.rs::Requester::send_request_async (gibt die SampleIdentity zurück); crates/rpc/src/replier.rs (Replier::receive_requests liefert PendingRequest::identity; AsyncReplierHandler erhält die Identität); runtime/cpp/include/dds/rpc.hpp (WriteSample::identity, Sample::identity); runtime/java/src/main/java/org/omg/dds/rpc/Sample.java (identity())

Tests: crates/rpc/tests/runtime_e2e.rs::e2e_client_side_request_identity_is_the_one_the_reply_relates_to, crates/rpc/src/replier.rs::tests::receive_requests_and_send_reply_expose_the_identity, crates/rpc/src/replier.rs::tests::dispatch_async_hands_the_replier_and_the_identity_to_the_listener

Status: done — die Identität ist am Requester und am Service abrufbar. Der synchrone ReplierHandler::handle der Rust-Laufzeit erhält nur den Wert des Requests; die Identität liefern receive_requests und der asynchrone Handler (c5af5c7c138e).

§7.2.3 Explizite und implizite Weitergabe

Spec: §7.2.3, S. 20 — “Explicit sample-identity implies that the request-id is visible in the top-level data type for the DDS topic. Implicit sample-identity, on the other hand, implies that the request sample-identity is communicated via extensibility mechanisms supported by the DDS-RTPS protocol. Specifically using the inlineQoS sub-message element.”

Repo: —

Tests: —

Status: n/a (informative) — Begriffe; die Pflichten stehen in §7.8.1 und §7.8.2.

§7.2.3 APIs für die request-id an Client und Service

Spec: §7.2.3, S. 20 — “In both cases, the specification provides APIs to get the request-id at the client side and get/set the request-id at the service side.”

Repo: crates/rpc/src/requester.rs::Requester::send_request_async; crates/rpc/src/replier.rs (Replier::receive_requests, Replier::send_reply mit RequestIdentity); runtime/cpp/include/dds/rpc.hpp (Replier::receive_requests, Replier::send_reply mit related_request_id); runtime/java/src/main/java/org/omg/dds/rpc/Replier.java (receiveRequests, sendReply(reply, relatedRequestId))

Tests: crates/rpc/tests/runtime_e2e.rs::e2e_client_side_request_identity_is_the_one_the_reply_relates_to, crates/rpc/src/replier.rs::tests::receive_requests_and_send_reply_expose_the_identity, crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together, crates/rpc/tests/java_rpc_runtime.rs::the_java_rpc_runtime_and_the_generated_services_run_together

Status: done — Lesen am Client und Lesen und Setzen am Service in Rust, C++ und Java. Rust am Service: c5af5c7c138e.

§7.2.4 Basic: keine Erweiterung von DDS und RTPS, explizite request-id

Spec: §7.2.4, S. 20 — “The Basic service mapping enables RPC over DDS functionality without any extensions to the [DDS] and [DDS-RTPS] specifications. It uses explicit request-id for correlation.”

Repo: crates/rpc/src/wire_codec.rs (encode_request_frame, encode_reply_frame); crates/rpc/src/requester.rs::Requester::tick; runtime/cpp/include/dds/rpc.hpp (RequestHeader::request_id, ReplyHeader::related_request_id); runtime/java/src/main/java/org/omg/dds/rpc/HeaderCodec.java

Tests: crates/rpc/src/requester.rs::tests::tick_correlates_reply_with_pending_slot, crates/rpc/tests/cpp_rpc_runtime.rs::the_two_headers_take_the_same_octets_in_both_columns, crates/rpc/tests/java_rpc_runtime.rs::the_two_headers_take_the_same_octets_in_both_columns

Status: done — alle drei Laufzeiten tragen die request-id im Header des Samples und brauchen für die Basic-Abbildung keine Erweiterung von DDS oder RTPS. C++ und Java füllen requestId mit der Identität des Writers: 58634aa2702a. Die Frage, ob in C++ diese Identität die vom Writer vergebene ist, steht im Item “Identität des Requests ist die des Samples”.

§7.2.4 Enhanced: Übersicht und Tabelle

Spec: §7.2.4, S. 20 — “The Enhanced service mapping uses implicit request-id for correlation, allows use of the additional data-types defined in DDS-XTypes, uses DDS-XTypes for type-compatibility checking, and provides more robust service discovery.” Dazu die Tabelle der Merkmale beider Abbildungen.

Repo: —

Tests: —

Status: n/a (informative) — Übersicht; jedes Merkmal ist in §7.4.3, §7.5.1.2, §7.6.2 und §7.8.2 einzeln geführt.

§7.2.5 Gleiche Abbildung auf beiden Seiten

Spec: §7.2.5, S. 20 — “Basic and Enhanced Service Mappings can be mixed in an application but for any given service both client and the service side must use the same service mapping.”

Repo: —

Tests: —

Status: n/a (informative) — Vorgabe an die Anwendung. Die Laufzeiten von ZeroDDS kennen Basic und Enhanced (RpcMapping::Basic und RpcMapping::Enhanced in crates/rpc/src/endpoint_options.rs); die Wahl trifft die Anwendung je Dienst.

§7.2.5 Abbildung unabhängig vom Stil

Spec: §7.2.5, S. 20 — “The Basic and Enhanced Service mappings are independent of the language binding style. For instance, it is possible for clients and service implementations to communicate using different language binding styles as long as their service mappings match.”

Repo: crates/rpc/src/requester.rs, crates/rpc/src/replier.rs, runtime/cpp/include/dds/rpc.hpp, runtime/java/src/main/java/org/omg/dds/rpc/ (jede Laufzeit hat Basic und Enhanced für beide Stile; RpcMapping bzw. ServiceMapping wählt die Abbildung, BindingStyle den Stil)

Tests: crates/rpc-rust-e2e/tests/e2e.rs::the_generated_calculator_binding_runs_every_call, crates/rpc-rust-e2e/tests/enhanced_e2e.rs::an_enhanced_call_is_answered_through_the_related_sample_identity, crates/rpc/tests/cpp_enhanced_function_call.rs::the_generated_enhanced_client_calls_the_generated_enhanced_service, crates/rpc-rust-e2e/tests/evolution_styles_discovery.rs::a_basic_function_call_client_calls_a_request_reply_service, crates/rpc-rust-e2e/tests/evolution_styles_discovery.rs::an_enhanced_function_call_client_calls_a_request_reply_service

Status: done — beide Abbildungen laufen mit beiden Stilen. Basic: ein Requester im Stil Request/Reply gegen den erzeugten Service im Stil Function-call (Tests im Item §7.2.2.3 “Vor- und Nachteile der Stile”) und umgekehrt a_basic_function_call_client_calls_a_request_reply_service. Enhanced: an_enhanced_function_call_client_calls_a_request_reply_service (Client im Stil Function-call, Replier im Stil Request/Reply, gleich gesetzte Namen der Topics enh_Calc_Service_Request und enh_Calc_Service_Reply; 414e077c527d).


§7.3 Service Definition

§7.3 Zwei Arten der Dienstdefinition

Spec: §7.3, S. 21 — “A service definition is provided using the following two alternatives. a) Interface […] b) A Pair of Types […] This specification uses OMG Interface Definition Language (IDL) or Java 1.5 as a concrete syntax to define services with either of the mechanisms above.”

Repo: —

Tests: —

Status: n/a (informative) — Übersicht; die Arten stehen in §7.3.1 bis §7.3.2.2 einzeln.

§7.3.1 Service Definition in IDL

Spec: §7.3.1, S. 21 — “This specification uses the interface definition syntax specified in [IDL]. Additionally, annotations are supported to provide extra information. […] this specification provides synchronous and asynchronous invocation capabilities only at the language binding level.”

Repo: —

Tests: —

Status: n/a (informative) — Einordnung; die Produktionen stehen in §7.3.1.1, die synchronen und asynchronen Aufrufe in §7.11.1.1.2.

§7.3.1.1 Produktion (1) specification

Spec: §7.3.1.1, S. 21 — “(1) ::= +”; Design Rationale, S. 22: “Modified to remove the CORBA-specific import statement.”

Repo: crates/idl-parse/src/decl.rs (Folge von Definitionen; parse_import); crates/rpc/src/service_mapping.rs::lower_service (weist import mit RpcError::OutsideServiceGrammar ab); crates/lang-rules/src/adapter/interface.rs::services (reject_outside_service_grammar weist import mit InterfaceError::OutsideServiceGrammar ab)

Tests: crates/idl-lower/tests/conformance.rs::the_xtypes_specifications_own_idl_lowers_completely, crates/rpc/src/service_mapping.rs::tests::an_import_directive_is_outside_the_service_grammar, crates/lang-rules/tests/interface_bindings.rs::the_seam_refuses_an_import_directive

Status: done — eine Folge von Definitionen wird gelesen. lower_service (Dienstmodell in Rust) weist import ab (1627b386b569), und der Pfad der Generatoren weist import ebenfalls ab (c9f99bb02dd5). Der Frontend crates/idl-parse liest weiterhin volles IDL 4.2 und nimmt import an; die Abweisung gilt an der Naht zu den Diensten, nicht im Parser.

§7.3.1.1 Produktion (2) definition

Spec: §7.3.1.1, S. 21 — “(2) ::= ”;” | “;” | “;” | “;” | “;” | “;” | “;” “; Design Rationale, S. 22: entfernt <type_id_dcl>, <type_prefix_dcl>, <event>, <component>, <home_dcl>; fügt Deklarationen von Annotationen hinzu.

Repo: crates/idl-parse/src/decl.rs (Definitionen, Deklaration @annotation, nachgestellte Annotationen //@); crates/rpc/src/service_mapping.rs::lower_service (weist typeid, typeprefix und component ab)

Tests: crates/rpc/src/annotations.rs::tests::dds_request_and_reply_topics_lower_and_resolve, crates/idl-parse/tests/parse.rs::a_suffix_annotation_reaches_the_tree_as_an_annotation, crates/rpc/src/service_mapping.rs::tests::a_typeid_directive_is_outside_the_service_grammar, crates/rpc/src/service_mapping.rs::tests::a_typeprefix_directive_is_outside_the_service_grammar, crates/rpc/src/service_mapping.rs::tests::a_component_declaration_is_outside_the_service_grammar, crates/lang-rules/tests/interface_bindings.rs::the_seam_refuses_typeid_and_typeprefix_directives, crates/lang-rules/tests/interface_bindings.rs::the_seam_refuses_a_component, crates/lang-rules/tests/interface_bindings.rs::the_seam_refuses_an_import_directive

Status: done — die verbliebenen Alternativen und Deklarationen von Annotationen werden gelesen. lower_service weist typeid, typeprefix und component ab (1627b386b569, 009e7a5ef119); dieselbe Prüfung macht crates/lang-rules/src/adapter/interface.rs::service für die Generatoren (c9f99bb02dd5).

§7.3.1.1 Produktion (7) interface_header mit Annotation

Spec: §7.3.1.1, S. 21 — “(7) ::= [ ] “interface” [ ]”.

Repo: crates/idl-parse/src/decl.rs; Annotationen am Interface gelesen in crates/rpc/src/annotations.rs::lower_rpc_annotations

Tests: crates/rpc/src/annotations.rs::tests::dds_request_and_reply_topics_lower_and_resolve, crates/rpc/src/service_mapping.rs::tests::every_base_interface_becomes_a_topic_alias, crates/rpc/src/service_mapping.rs::tests::a_local_interface_is_outside_the_service_grammar

Status: done — Annotationen am Interface werden gelesen (c9f21d8f9a8e); lower_service weist andere Formen als interface (local, abstract, component) ab (009e7a5ef119).

§7.3.1.1 Produktion (9) export

Spec: §7.3.1.1, S. 22 — “(9) ::= “;” | “;””; Design Rationale, S. 23: “This production also removes the rules that allow embedding declarations of types, constants, and exceptions within an interface.”

Repo: crates/lang-rules/src/adapter/interface.rs::service (Operationen und Attribute); crates/rpc/src/service_mapping.rs::lower_service (Operationen und Attribute; Konstanten, Typen und Exceptions im Interface ergeben RpcError::OutsideServiceGrammar)

Tests: crates/lang-rules/tests/interface_bindings.rs::the_seam_reads_every_part_of_an_interface, crates/rpc/src/service_mapping.rs::tests::a_nested_declaration_is_outside_the_service_grammar, crates/rpc/src/service_mapping.rs::tests::a_nested_type_declaration_is_outside_the_service_grammar, crates/lang-rules/tests/interface_bindings.rs::the_seam_refuses_a_type_in_an_interface_body, crates/lang-rules/tests/interface_bindings.rs::the_seam_refuses_a_constant_in_an_interface_body, crates/lang-rules/tests/interface_bindings.rs::the_seam_refuses_an_exception_in_an_interface_body

Status: done — in lower_service ist ein Member außer Attribut und Operation ein Fehler (1627b386b569). crates/lang-rules/src/adapter/interface.rs::service weist eine Konstante, einen Typ und eine Exception im Interface mit InterfaceError::OutsideServiceGrammar ab (c9f99bb02dd5).

§7.3.1.1 Produktion (42) type_dcl mit Annotation

Spec: §7.3.1.1, S. 22 — “(42) ::= [ ] “typedef” | [ ] | | | “native” | ”.

Repo: crates/idl-parse/src/decl.rs; crates/idl-lower/src/annotation.rs

Tests: crates/idl-parse/tests/parse.rs::annotations_bind_to_the_declaration_that_follows, crates/idl-lower/tests/annotations.rs::an_alias_supplies_a_default_that_the_use_site_overrides

Status: done — Annotationen an Typdeklarationen werden gelesen (b0a9331d9221).

§7.3.1.1 Produktion (87) op_dcl

Spec: §7.3.1.1, S. 22 — “(87) ::= [ ] [ ]”; Design Rationale, S. 23: “Removed the CORBA-specific “oneway” modifier and the “context” expressions.”

Repo: crates/idl-parse/src/decl.rs; crates/rpc/src/service_mapping.rs::lower_method (weist oneway, @oneway und context ab)

Tests: crates/rpc/src/service_mapping.rs::tests::the_oneway_keyword_is_outside_the_service_grammar, crates/rpc/src/service_mapping.rs::tests::the_oneway_annotation_is_outside_the_service_grammar, crates/rpc/src/service_mapping.rs::tests::a_context_clause_is_outside_the_service_grammar, crates/lang-rules/tests/interface_bindings.rs::the_seam_refuses_a_oneway_operation, crates/lang-rules/tests/interface_bindings.rs::the_seam_refuses_the_oneway_annotation, crates/lang-rules/tests/interface_bindings.rs::the_seam_refuses_a_context_clause

Status: done — lower_service weist das Wort oneway, @oneway und eine context-Klausel mit RpcError::OutsideServiceGrammar ab (1627b386b569, cc78028ceb52). Der Leser der Generatoren (crates/lang-rules/src/adapter/interface.rs::one_operation) weist sie mit InterfaceError::OutsideServiceGrammar ab (c9f99bb02dd5); die Quellen der Tests der Generatoren und von crates/rpc-rust-e2e enthalten kein oneway mehr (83ead28f9c52). Das Feld Operation::oneway und die Zweige für oneway in emit/interface_{cpp,java,rust,typescript}.rs und in crates/webdds-bridge sind entfernt (31247aca290). Die Design Rationale der Produktion nennt die Entfernung („Removed the CORBA-specific “oneway” modifier and the “context” expressions.“); §7.3.2 behält @oneway nur für Java-Quellen (java_service_def). Das IDL-@oneway wird ebenfalls abgewiesen: die Zeile der Rationale betrifft die IDL-Grammatik, und eine Annotation nur für Java hat keine Abbildung in den Topic-Typen.

§7.3.1.1 Produktion (91) param_dcl mit Annotation

Spec: §7.3.1.1, S. 22 — “(91) ::= [ ] ”.

Repo: crates/rpc/src/service_mapping.rs::lower_method (Annotationen am Parameter, override_direction)

Tests: crates/rpc/src/service_mapping.rs::tests::param_annotation_in_overrides_declared_direction, crates/idl-lower/tests/conformance.rs::the_xtypes_specifications_own_idl_lowers_completely

Status: done — Annotationen am Parameter ändern die Richtung (52a3f267a6d7).

§7.3.1.1 Produktion (104) readonly_attr_spec mit Annotation

Spec: §7.3.1.1, S. 22 — “(104) ::= [ ] “readonly” “attribute” ”.

Repo: crates/idl-parse/src/decl.rs

Tests: crates/idl-lower/tests/conformance.rs::the_xtypes_specifications_own_idl_lowers_completely (@key readonly attribute long version; in dds_xtypes.idl)

Status: done — der Frontend liest die Annotation vor readonly attribute (784e1e121a5f).

§7.3.1.1 Produktion (106) attr_spec mit Annotation

Spec: §7.3.1.1, S. 22 — “(106) ::= [ ] “attribute” ”.

Repo: crates/idl-parse/src/decl.rs

Tests: crates/idl-parse/tests/parse.rs::annotations_bind_to_the_declaration_that_follows, crates/idl-parse/tests/parse.rs::an_annotation_precedes_a_writable_attribute

Status: done — der Frontend liest Annotationen vor Deklarationen allgemein; der Test mit @id(1) attribute long x; (ohne readonly) zeigt die Annotation als erstes Kind des Knotens AttributeDecl (eb2c0e0f8f47).

§7.3.1.1 Produktion (106) attr_spec: Test mit schreibbarem Attribut

Spec: §7.3.1.1, S. 22 — wie oben.

Repo: crates/idl-parse/src/decl.rs

Tests: crates/idl-parse/tests/parse.rs::an_annotation_precedes_a_writable_attribute

Status: done — an_annotation_precedes_a_writable_attribute parst interface I { @id(1) attribute long x; }; ohne Diagnostik und prüft, dass der Knoten kein readonly enthält (eb2c0e0f8f47).

§7.3.1.1 — Konstrukte außerhalb der Grammatik der Abbildung

Spec: §7.3.1.1, S. 21–23 — “The IDL 3.5 grammar shall be modified with the productions shown below.” Die Design Rationale nennt, was entfällt: import, <type_id_dcl>, <type_prefix_dcl>, <event>, <component>, <home_dcl>, Deklarationen von Typen, Konstanten und Exceptions im Interface, oneway, context.

Repo: crates/rpc/src/service_mapping.rs::lower_service und lower_method (RpcError::OutsideServiceGrammar in crates/rpc/src/error.rs für import, typeid/typeprefix, component/home/local/abstract, Typ-, Konstanten- und Exception-Deklarationen im Interface, oneway, @oneway, context); crates/idl-lower/src/lower.rs und crates/ast/src/facet/corba.rs (repository_directives für typeid und typeprefix)

Tests: crates/rpc/src/service_mapping.rs::tests::the_oneway_keyword_is_outside_the_service_grammar, crates/rpc/src/service_mapping.rs::tests::the_oneway_annotation_is_outside_the_service_grammar, crates/rpc/src/service_mapping.rs::tests::a_context_clause_is_outside_the_service_grammar, crates/rpc/src/service_mapping.rs::tests::a_nested_declaration_is_outside_the_service_grammar, crates/rpc/src/service_mapping.rs::tests::a_nested_type_declaration_is_outside_the_service_grammar, crates/rpc/src/service_mapping.rs::tests::an_import_directive_is_outside_the_service_grammar, crates/rpc/src/service_mapping.rs::tests::a_typeid_directive_is_outside_the_service_grammar, crates/rpc/src/service_mapping.rs::tests::a_typeprefix_directive_is_outside_the_service_grammar, crates/rpc/src/service_mapping.rs::tests::a_component_declaration_is_outside_the_service_grammar, crates/rpc/src/service_mapping.rs::tests::a_local_interface_is_outside_the_service_grammar, crates/lang-rules/tests/interface_bindings.rs::the_seam_refuses_a_oneway_operation, crates/lang-rules/tests/interface_bindings.rs::the_seam_refuses_a_context_clause, crates/lang-rules/tests/interface_bindings.rs::the_seam_refuses_a_type_in_an_interface_body, crates/lang-rules/tests/interface_bindings.rs::the_seam_refuses_a_constant_in_an_interface_body, crates/lang-rules/tests/interface_bindings.rs::the_seam_refuses_an_exception_in_an_interface_body, crates/lang-rules/tests/interface_bindings.rs::the_seam_refuses_an_import_directive, crates/lang-rules/tests/interface_bindings.rs::the_seam_refuses_typeid_and_typeprefix_directives, crates/lang-rules/tests/interface_bindings.rs::the_seam_refuses_an_abstract_interface, crates/lang-rules/tests/interface_bindings.rs::the_seam_refuses_a_component, crates/lang-rules/tests/interface_bindings.rs::a_local_interface_is_refused_by_the_seam

Status: done — das Dienstmodell in Rust (lower_service) weist die entfallenen Konstrukte mit RpcError::OutsideServiceGrammar ab (1627b386b569, 009e7a5ef119). Dieselbe Prüfung macht der Leser der Generatoren, crates/lang-rules/src/adapter/interface.rs::service und services (von idlc generate benutzt), mit InterfaceError::OutsideServiceGrammar (c9f99bb02dd5); a_local_interface_is_refused_by_the_seam zeigt zusätzlich, dass cpp_interface_items und java_interface_items für ein local interface fehlschlagen. Der Frontend (crates/idl-parse) liest volles IDL 4.2 und hat kein Profil der Grammatik von §7.3.1.1; die Abweisung liegt in lower_service und im Leser der Generatoren.

§7.3.1.1 Annotationen der Basic-Abbildung bleiben nicht im Ergebnis

Spec: §7.3.1.1, S. 23 — “The Basic Service Mapping uses annotations only for interface declarations and not on regular type declarations. These interface annotations are resolved in the mapping such that the resulting IDL used by DDS does not have annotations.”

Repo: crates/lang-rules/src/emit/interface_cpp.rs::declare (die synthetisierten Typen sind Strukturen ohne Annotation)

Tests: crates/lang-rules/tests/interface_bindings.rs::cpp_declares_the_topic_types_of_seven_five

Status: done — Commit ad892a10764a.

§7.3.1.2 Typsystem von XTypes in Signaturen (Enhanced)

Spec: §7.3.1.2, S. 23 — “The Enhanced Service Mapping allows use of the full type-system defined in the DDS-XTypes specification in the declaration of interface attributes, operation parameters, and return values. […] extends the IDL productions defined in the Basic Service Mapping with all the productions […] in sub clause 7.3.1.12.1 (New Productions) of the DDS-XTypes specification.”

Repo: crates/idl-parse/, crates/idl-lower/ (IDL 4.2 mit den Typen von XTypes 1.3)

Tests: crates/idl-lower/tests/conformance.rs::the_xtypes_specifications_own_idl_lowers_completely

Status: done — Commit 784e1e121a5f.

§7.3.1.2 Geänderte Produktionen von XTypes, wie Basic

Spec: §7.3.1.2, S. 23 — “In addition, the Enhanced Service Mapping also uses all the modified productions defined in sub clause 7.3.1.12.2 (Modified Productions) of the [DDS-Xtypes] specification with the exception of the production for , which shall remain, as defined for the Basic Service Mapping.”

Repo: crates/idl-parse/src/decl.rs; crates/rpc/src/service_mapping.rs::lower_service

Tests: crates/idl-lower/tests/conformance.rs::the_xtypes_specifications_own_idl_lowers_completely, crates/rpc/src/service_mapping.rs::tests::a_nested_declaration_is_outside_the_service_grammar, crates/lang-rules/tests/interface_bindings.rs::the_seam_refuses_a_type_in_an_interface_body, crates/lang-rules/tests/interface_bindings.rs::the_seam_refuses_a_constant_in_an_interface_body

Status: done — die geänderten Produktionen von XTypes liest der Frontend. <definition> bleibt für das Dienstmodell in Rust (lower_service, 1627b386b569) und für den Leser der Generatoren in crates/lang-rules (c9f99bb02dd5) die der Basic-Abbildung; der Frontend selbst liest IDL 4.2 (Item „§7.3.1.1 — Konstrukte außerhalb der Grammatik der Abbildung“ oben).

§7.3.1.3 Example of an Interface in IDL

Spec: §7.3.1.3, S. 23–24 — Beispiel robot::RobotControl (“Non-normative”).

Repo: —

Tests: —

Status: n/a (informative) — Beispiel.

§7.3.1.4 Paar von Typen mit @RPCRequestType und @RPCReplyType

Spec: §7.3.1.4, S. 24 — “A service definition may simply include a pair of types, which may be the same. The request and reply types shall be marked as such using the @RPCRequestType and @RPCReplyType annotations.”

Repo: crates/rpc/src/type_pair.rs::lower_type_pairs (liest die Paare aus einem Modell; TypePairService); crates/rpc/src/annotations.rs::lower_single (RpcAnnotation::RpcRequestType, RpcAnnotation::RpcReplyType); crates/ast/src/node/annotation.rs (BUILTIN_ANNOTATIONS, die Annotationen brauchen keine Deklaration)

Tests: crates/rpc/src/type_pair.rs::tests::a_marked_pair_with_headers_is_a_basic_service, crates/rpc/src/type_pair.rs::tests::one_type_may_be_both_halves, crates/rpc/src/annotations.rs::tests::the_pair_annotations_lower_and_resolve, crates/rpc/src/annotations.rs::tests::the_spec_annotations_need_no_declaration

Status: done — 6c7f585a36ee (vordefinierte Annotationen), 1e28b13546c1 (lower_type_pairs; @RPCRequest und @RPCReply, die die Spec nicht kennt, entfernt).

§7.3.1.4 Auswertung des Paars von Typen in IDL

Spec: §7.3.1.4, S. 24 — wie oben.

Repo: crates/rpc/src/type_pair.rs::lower_type_pairs; crates/lang-rules/src/emit/type_pair_rust.rs, crates/lang-rules/src/emit/type_pair_cpp.rs, crates/lang-rules/src/emit/type_pair_java.rs (erzeugte Bindung über den Endpunkten, has_pair_types)

Tests: crates/lang-rules/tests/type_pair_rust.rs::a_pair_with_headers_gets_the_header_traits_and_the_endpoints, crates/lang-rules/tests/type_pair_rust.rs::the_service_name_is_read_from_either_annotation_and_can_be_given_at_run_time, crates/lang-rules/tests/type_pair_cpp.rs::a_pair_with_headers_gets_traits_and_support, crates/lang-rules/tests/type_pair_cpp.rs::the_service_name_is_run_time_then_annotation_then_default, crates/lang-rules/tests/type_pair_java.rs::the_generated_pair_declares_the_support_and_uses_the_runtimes_headers, crates/rpc/src/type_pair.rs::tests::the_service_name_comes_from_either_annotation_on_either_type

Status: done — lower_type_pairs macht aus einem Paar markierter Typen einen Dienst (1e28b13546c1). Die Generatoren erzeugen eine Bindung dafür: Rust d9446301d9b1, C++ 83d80ac9bf48 und 35a69aa60d98, Java f46b42ca8b3a (Laufzeit) und 639d549b4bfd (Generator). Der Name des Dienstes kommt aus @service oder @DDSService an einem der Typen oder zur Laufzeit (f641beefbe78). Java: crates/lang-rules/tests/type_pair_java.rs hat Tests; ihr Namensabgleich wurde hier nicht geprüft.

§7.3.1.4 Nur Strukturen als Typen des Paars

Spec: §7.3.1.4, S. 24 — “Only struct types shall be marked as request/reply types.”

Repo: crates/rpc/src/type_pair.rs::lower_type_pairs (RpcError::InvalidTypePair für einen markierten Typ, der keine Struktur ist)

Tests: crates/rpc/src/type_pair.rs::tests::a_marked_type_that_is_not_a_struct_is_refused, crates/lang-rules/tests/type_pair_rust.rs::a_marked_type_that_is_not_a_struct_is_refused

Status: done — 1e28b13546c1.

§7.3.1.4 Basic: Member header im Paar von Typen

Spec: §7.3.1.4, S. 24 — “In the Basic Service Mapping, the types annotated as @RPCRequestType shall have a member named header of type dds::rpc::RequestHeader and the types annotated as @RPCReplyType shall have a member named header of type dds::rpc::RequestHeader.”

Repo: crates/rpc/src/type_pair.rs::lower_type_pairs (header_type; Request-Typ: dds::rpc::RequestHeader; Reply-Typ: dds::rpc::ReplyHeader, mit TypePairOptions::reply_header auf dds::rpc::RequestHeader umstellbar)

Tests: crates/rpc/src/type_pair.rs::tests::a_marked_pair_with_headers_is_a_basic_service, crates/rpc/src/type_pair.rs::tests::a_header_of_the_wrong_type_is_refused, crates/rpc/src/type_pair.rs::tests::a_header_in_only_one_type_is_refused, crates/rpc/src/type_pair.rs::tests::the_reply_header_type_is_a_setting

Status: done — 1e28b13546c1. Für den Reply-Typ nennt der Satz der Spec dds::rpc::RequestHeader; §7.5.1.1.1 definiert ReplyHeader, und RequestHeader hat kein related_request_id. Voreinstellung ist ReplyHeader; der Wortlaut des Satzes ist über TypePairOptions::reply_header wählbar.

§7.3.1.4 Enhanced: keine Annotationen, keine besonderen Member

Spec: §7.3.1.4, S. 24 — “When using the Enhanced Service Mapping, the annotations are not necessary and the special data members must not be defined.”

Repo: crates/rpc/src/type_pair.rs::lower_type_pairs (PairMapping::Enhanced für ein Paar ohne header-Member in beiden Typen)

Tests: crates/rpc/src/type_pair.rs::tests::a_marked_pair_without_headers_is_an_enhanced_service, crates/lang-rules/tests/type_pair_rust.rs::a_pair_without_headers_is_the_enhanced_mapping, crates/lang-rules/tests/type_pair_cpp.rs::a_pair_without_headers_is_the_enhanced_mapping, crates/lang-rules/tests/type_pair_java.rs::the_enhanced_pair_has_no_header_and_selects_the_enhanced_mapping, crates/rpc/src/type_pair.rs::tests::a_header_in_only_one_type_is_refused

Status: done — 1e28b13546c1. Ein Paar ohne header-Member ist Enhanced; ein header in nur einem Typ wird abgewiesen. Ein Paar wird am Modell nur an den Annotationen erkannt; Typen ohne Annotation bilden kein Paar, und die Spec nennt kein anderes Merkmal.

§7.3.2 Java: InterfaceDeclaration

Spec: §7.3.2, S. 24 — “Conforming implementations shall support the syntax generated by the following modified productions from the Java grammar. […] InterfaceDeclaration: NormalInterfaceDeclaration”; Design Rationale, S. 25: “Removed annotation type declaration.”

Repo: crates/rpc/src/java_service_def.rs::parse

Tests: crates/rpc/src/java_service_def.rs::tests::the_example_of_seven_three_two_one_parses, crates/rpc/src/java_service_def.rs::tests::the_removed_productions_are_refused

Status: done — ad892a10764a.

§7.3.2 Java: NormalInterfaceDeclaration

Spec: §7.3.2, S. 24 — “NormalInterfaceDeclaration: interface Identifier [extends TypeList] InterfaceBody”; Design Rationale, S. 25: “Removed generic type parameters.”

Repo: crates/rpc/src/java_service_def.rs (Cursor::interface)

Tests: crates/rpc/src/java_service_def.rs::tests::the_extends_list_survives, crates/rpc/src/java_service_def.rs::tests::the_removed_productions_are_refused

Status: done — ad892a10764a.

§7.3.2 Java: InterfaceBody

Spec: §7.3.2, S. 24 — “InterfaceBody: { InterfaceBodyDeclaration {InterfaceBodyDeclaration} }”; Design Rationale, S. 25: “At least one method must be present in an interface.”

Repo: crates/rpc/src/java_service_def.rs (Cursor::interface)

Tests: crates/rpc/src/java_service_def.rs::tests::an_empty_interface_body_is_refused, crates/rpc/src/java_service_def.rs::tests::the_example_of_seven_three_two_one_parses

Status: done — ad892a10764a.

§7.3.2 Java: InterfaceMemberDecl

Spec: §7.3.2, S. 24 — “InterfaceMemberDecl: InterfaceMethodOrFieldDecl void Identifier VoidInterfaceMethodDeclaratorRest InterfaceDeclaration ClassDeclaration”; Design Rationale, S. 25: “Removed generic method declaration.”

Repo: crates/rpc/src/java_service_def.rs (Cursor::interface, Cursor::method)

Tests: crates/rpc/src/java_service_def.rs::tests::a_return_type_and_a_void_are_told_apart, crates/rpc/src/java_service_def.rs::tests::a_nested_declaration_is_kept, crates/rpc/src/java_service_def.rs::tests::a_field_in_an_interface_body_is_a_constant

Status: done — Methoden, void-Methoden und verschachtelte Deklarationen werden gelesen. Ein Feld im Interface-Körper liest Cursor::interface als Konstante (JavaInterface::constants), auch mit Dimensionen und mehreren Deklaratoren; ein Feld ohne Wert wird mit RpcError::JavaSyntax abgewiesen (29381ca02054).

§7.3.2 Java: NormalClassDeclaration

Spec: §7.3.2, S. 24 — “NormalClassDeclaration: class Identifier [extends Type] [implements TypeList] ClassBody”; Design Rationale, S. 25: “Removed generic type parameters.”

Repo: crates/rpc/src/java_service_def.rs (Cursor::class)

Tests: crates/rpc/src/java_service_def.rs::tests::the_example_of_seven_three_two_one_parses, crates/rpc/src/java_service_def.rs::tests::the_removed_productions_are_refused, crates/rpc/src/java_service_def.rs::tests::the_implements_list_of_a_class_survives

Status: done — class, extends, implements (JavaClass::implements) und die Abweisung von Generics sind getestet (29381ca02054).

§7.3.2 Java: ClassBody

Spec: §7.3.2, S. 24–25 — “ClassBody: { ClassBodyDeclaration {ClassBodyDeclaration} }”; Design Rationale, S. 25: “At least one data member must be defined in the class body.”

Repo: crates/rpc/src/java_service_def.rs (Cursor::class)

Tests: crates/rpc/src/java_service_def.rs::tests::an_empty_class_body_is_refused, crates/rpc/src/java_service_def.rs::tests::the_pair_of_types_of_seven_three_two_two_is_found

Status: done — ad892a10764a.

§7.3.2 Java: ClassBodyDeclaration

Spec: §7.3.2, S. 25 — “ClassBodyDeclaration: ; {Modifier} MemberDecl”; Design Rationale, S. 25: “Removed Java’s static block support.”

Repo: crates/rpc/src/java_service_def.rs (Cursor::class, Cursor::modifiers)

Tests: crates/rpc/src/java_service_def.rs::tests::the_removed_productions_are_refused, crates/rpc/src/java_service_def.rs::tests::the_pair_of_types_of_seven_three_two_two_is_found

Status: done — ad892a10764a.

§7.3.2 Java: MemberDecl

Spec: §7.3.2, S. 25 — “MemberDecl: MethodOrFieldDecl”; Design Rationale, S. 25: “This specification shall support data member declarations inside a Java class.”

Repo: crates/rpc/src/java_service_def.rs (Cursor::class, JavaClass::fields)

Tests: crates/rpc/src/java_service_def.rs::tests::the_pair_of_types_of_seven_three_two_two_is_found, crates/rpc/src/java_service_def.rs::tests::the_removed_productions_are_refused

Status: done — ad892a10764a.

§7.3.2 Java: MethodOrFieldRest

Spec: §7.3.2, S. 25 — “MethodOrFieldRest: VariableDeclaratorRest”; Design Rationale, S. 25: “Removed method declarator.”

Repo: crates/rpc/src/java_service_def.rs (Cursor::class)

Tests: crates/rpc/src/java_service_def.rs::tests::the_pair_of_types_of_seven_three_two_two_is_found, crates/rpc/src/java_service_def.rs::tests::dimensions_after_the_name_belong_to_the_type, crates/rpc/src/java_service_def.rs::tests::an_initialised_member_is_read_without_its_value, crates/rpc/src/java_service_def.rs::tests::several_declarators_share_one_type, crates/rpc/src/java_service_def.rs::tests::a_field_does_not_make_a_method_acceptable_in_a_class

Status: done — ein Feld mit und ohne Initialisierung, mehrere Deklaratoren (int a, b;) und Dimensionen nach dem Namen (int a[];, addiert zu den Dimensionen des Typs) werden gelesen und getestet (29381ca02054).

§7.3.2 Java: Feld im Interface, implements und VariableDeclaratorRest

Spec: §7.3.2, S. 24–25 — wie oben.

Repo: crates/rpc/src/java_service_def.rs (Cursor::interface, Cursor::class)

Tests: crates/rpc/src/java_service_def.rs::tests::a_field_in_an_interface_body_is_a_constant, crates/rpc/src/java_service_def.rs::tests::dimensions_after_the_name_belong_to_the_type, crates/rpc/src/java_service_def.rs::tests::an_initialised_member_is_read_without_its_value, crates/rpc/src/java_service_def.rs::tests::several_declarators_share_one_type, crates/rpc/src/java_service_def.rs::tests::the_implements_list_of_a_class_survives

Status: done — ein Feld im Interface-Körper ist eine Konstante und braucht einen Wert; Dimensionen nach dem Namen, Initialisierung, mehrere Deklaratoren und implements sind gelesen und getestet (29381ca02054).

§7.3.2 Java: @in, @out, @inout

Spec: §7.3.2, S. 25 — “In, out, and inout parameters are specified using the @in, @out and @inout annotations. By default the parameters are read only, and the use of @in is optional.”

Repo: crates/rpc/src/java_service_def.rs::direction_of

Tests: crates/rpc/src/java_service_def.rs::tests::the_direction_annotations_of_seven_three_two_are_read

Status: done — ad892a10764a.

§7.3.2 Java: @oneway

Spec: §7.3.2, S. 25 — “One or more operations may be marked oneway using the @oneway annotation.”

Repo: crates/rpc/src/java_service_def.rs (Cursor::method, JavaMethod::oneway)

Tests: crates/rpc/src/java_service_def.rs::tests::the_oneway_annotation_is_read_and_checked

Status: done — ad892a10764a.

§7.3.2.1 Example of an interface in Java

Spec: §7.3.2.1, S. 26 — Beispiel RobotControl (“Non-normative”).

Repo: —

Tests: —

Status: n/a (informative) — Beispiel.

§7.3.2.2 Java: Paar von Typen mit @RPCRequestType und @RPCReplyType

Spec: §7.3.2.2, S. 26 — “A service definition may simply include a pair of types, which may be the same. The request and reply types shall be marked as such using the @RPCRequestType and @RPCReplyType annotations.”

Repo: crates/rpc/src/java_service_def.rs::request_reply_pair

Tests: crates/rpc/src/java_service_def.rs::tests::the_pair_of_types_of_seven_three_two_two_is_found, crates/rpc/src/java_service_def.rs::tests::one_class_may_be_both_halves_of_the_pair

Status: done — ad892a10764a.

§7.3.2.2 Java: nur Klassen als Typen des Paars

Spec: §7.3.2.2, S. 26 — “Only class types shall be marked as request/reply types.”

Repo: crates/rpc/src/java_service_def.rs::request_reply_pair (betrachtet nur Klassen)

Tests: crates/rpc/src/java_service_def.rs::tests::the_pair_of_types_of_seven_three_two_two_is_found, crates/rpc/src/java_service_def.rs::tests::a_marked_interface_is_reported

Status: done — request_reply_pair meldet ein markiertes Interface, welche Hälfte auch immer, mit RpcError::InvalidTypePair („only class types“) (29381ca02054).

§7.3.2.2 Java Basic: Member header vom Typ dds.rpc.RequestHeader

Spec: §7.3.2.2, S. 26 — “In the Basic Service Mapping, the types annotated as @RPCRequestType shall have a member named header of type dds.rpc.RequestHeader and the types annotated as @RPCReplyType shall have a member named header of type dds.rpc.RequestHeader.”

Repo: crates/rpc/src/java_service_def.rs::request_reply_pair, JavaClass::has_header_member

Tests: crates/rpc/src/java_service_def.rs::tests::the_type_of_the_header_member_is_checked, crates/rpc/src/java_service_def.rs::tests::a_header_in_only_one_class_is_reported

Status: done — request_reply_pair prüft den Typ von header (dds.rpc.RequestHeader für den Request-Typ, dds.rpc.ReplyHeader für den Reply-Typ, mit TypePairOptions::reply_header auf RequestHeader umstellbar) und meldet ein header in nur einer Klasse (29381ca02054).

§7.3.2.2 — Prüfungen des Paars in Java

Spec: §7.3.2.2, S. 26 — wie die beiden Items oben.

Repo: crates/rpc/src/java_service_def.rs::request_reply_pair

Tests: crates/rpc/src/java_service_def.rs::tests::a_marked_interface_is_reported, crates/rpc/src/java_service_def.rs::tests::the_type_of_the_header_member_is_checked, crates/rpc/src/java_service_def.rs::tests::a_header_in_only_one_class_is_reported, crates/rpc/src/java_service_def.rs::tests::an_incomplete_or_ambiguous_pair_is_reported, crates/rpc/src/java_service_def.rs::tests::no_marked_class_is_no_pair

Status: done — ein markiertes Interface, ein falscher Typ von header, ein header in nur einer Klasse, eine fehlende Hälfte und zwei Klassen derselben Hälfte ergeben RpcError::InvalidTypePair, wie crates/rpc/src/type_pair.rs es für IDL tut (29381ca02054). Ohne markierte Klasse gibt es kein Paar und keinen Fehler.

§7.3.2.2 Java Enhanced: keine Annotationen, keine besonderen Member

Spec: §7.3.2.2, S. 26 — “When using the Enhanced Service Mapping, the annotations are not necessary and the special data members must not be defined.”

Repo: crates/rpc/src/java_service_def.rs::request_reply_pair (JavaTypePair::mapping, PairMapping)

Tests: crates/rpc/src/java_service_def.rs::tests::a_pair_without_headers_is_an_enhanced_pair, crates/rpc/src/java_service_def.rs::tests::a_header_in_only_one_class_is_reported

Status: done — request_reply_pair entscheidet wie PairMapping in crates/rpc/src/type_pair.rs: header in beiden Klassen ist Basic, in keiner Enhanced, in einer ein Fehler (29381ca02054). Die Java-Bindung für ein Paar aus IDL (crates/lang-rules/src/emit/type_pair_java.rs, ServiceMapping.ENHANCED) ist davon unabhängig.


§7.4 Mapping Service Specification to DDS Topics

§7.4.1 aus Interface, Service-Name und Suffix

Spec: §7.4.1, S. 26 — “ ::= “” “” [ “Request” | “Reply” ] | ”.

Repo: crates/rpc/src/topic_naming.rs (compose_topic_name, ServiceTopicNames::synthesize); crates/lang-rules/src/adapter/interface.rs::Service::request_topic_name

Tests: crates/rpc/src/topic_naming.rs::tests::the_default_name_carries_the_service_segment, crates/rpc/src/service_mapping.rs::tests::calculator_service_with_in_params_lowers

Status: done — 4f3b0f132d8a.

§7.4.1 als Name des Benutzers

Spec: §7.4.1, S. 26 — “Topic name is either a user-defined string literal or a composite string consisting and .”

Repo: crates/rpc/src/topic_naming.rs::ServiceTopicNames::one (ganzer Name aus der Annotation)

Tests: crates/rpc/src/topic_naming.rs::tests::an_annotation_gives_the_whole_name_and_no_alias, crates/rpc/tests/runtime_e2e.rs::e2e_annotated_whole_topic_name_replaces_the_default_dds_rpc_1_0_section_7_4_2_2

Status: done — 4f3b0f132d8a (Namen), 77bb7cba7e6d (Requester und Replier nehmen den Namen aus der Annotation).

§7.4.1 mit Vorgabe “Service”

Spec: §7.4.1, S. 26–27 — “ ::= “Service” | […] The non-terminal may be user-supplied. When it is not, it defaults to “Service.””

Repo: crates/rpc/src/topic_naming.rs::DEFAULT_SERVICE_NAME; crates/rpc/src/service_mapping.rs::lower_service

Tests: crates/rpc/src/service_mapping.rs::tests::without_the_annotation_the_service_segment_is_the_default, crates/rpc/src/topic_naming.rs::tests::service_topic_names_pair

Status: done — 4f3b0f132d8a.

§7.4.1

Spec: §7.4.1, S. 26–27 — “ ::= 1+$ […] a regular expression that includes alphanumeric characters (a-zA-Z0-9), underscore and space.”

Repo: crates/rpc/src/topic_naming.rs::validate_user_def_alpha_num

Tests: crates/rpc/src/topic_naming.rs::tests::the_published_character_set_admits_a_space_and_a_leading_digit, crates/rpc/src/topic_naming.rs::tests::everything_outside_the_set_is_refused

Status: done — 4f3b0f132d8a. ### §7.4.1 voll qualifiziert

Spec: §7.4.1, S. 26 — “The non-terminal represents the fully-qualified name of the interface, which is captured automatically for interface-based service definitions. A fully qualified interface-name includes concatenation of module names separates by underscores followed by the name of the interface.”

Repo: crates/rpc/src/topic_naming.rs::qualified_interface_name; crates/rpc/src/service_mapping.rs (qualified_name_of); crates/lang-rules/src/adapter/interface.rs::qualified_interface_name

Tests: crates/rpc/src/topic_naming.rs::tests::the_interface_segment_is_the_fully_qualified_name, crates/rpc/src/service_mapping.rs::tests::the_module_chain_reaches_the_topic_name

Status: done — Code und Tests vorhanden. Commit 4f3b0f132d8a (der Topic-Name ist <interface>_<service>_Request).

§7.4.1 Angegebener mit den Suffixen Request und Reply

Spec: §7.4.1, S. 27 — “If the is specified by the user, “Request” and “Reply” topic suffixes are used automatically.”

Repo: crates/rpc/src/topic_naming.rs::ServiceTopicNames::one (Schritt 3); in IDL über @service(name = "…") (IDL 4.2), gelesen in crates/rpc/src/annotations.rs::lower_service_annotation

Tests: crates/rpc/src/topic_naming.rs::tests::a_user_supplied_service_name_replaces_only_that_segment, crates/rpc/src/service_mapping.rs::tests::the_service_annotation_supplies_the_service_segment_only

Status: done — Code und Tests vorhanden. Commits 4f3b0f132d8a (Bildung der Namen), 52a3f267a6d7 (Lesen von @service).

§7.4.1 Java: aus @DDSService

Spec: §7.4.1, S. 26–27 — wie oben: der Benutzer liefert <service_name>; <interface_name> wird aus dem Interface übernommen.

Repo: crates/rpc/src/java_service_def.rs (JavaInterface::service_name, JavaServiceDef::service_name, JavaServiceDef::topic_names); crates/lang-rules/src/emit/interface_java.rs (erzeugte Support-Klasse setzt interfaceName und annotatedServiceName)

Tests: crates/rpc/src/java_service_def.rs::tests::the_service_annotation_overrides_the_interface_name, crates/rpc/tests/java/FunctionCallRoundtrip.java (Prüfung von TopicNames.of(named); gefahren von crates/rpc/tests/java_rpc_runtime.rs)

Status: done — @DDSService(name = "…") liefert <service_name>, <interface_name> bleibt der Name des Interface: Calculator_Arithmetic_Request. Ohne Namen gilt Service. Commits b7f5da73ca28 (Rust-Leser), 53ae2ab01af5 (erzeugte Java-Support-Klasse nennt das Interface für einen Service-Namen zur Laufzeit).

§7.4.1 Vorrang angegebener Topic-Namen vor dem Service-Namen

Spec: §7.4.1, S. 27 — “When and user-defined topic names are both provided by the user, the user-defined topic names take precedence.”

Repo: crates/rpc/src/topic_naming.rs::ServiceTopicNames::one; C++: runtime/cpp/include/dds/rpc/core.hpp::dds::rpc::synthesize_topic_names; Java: runtime/java/src/main/java/org/omg/dds/rpc/TopicNames.java::resolve

Tests: crates/lang-rules/tests/interface_bindings.rs::cpp_carries_the_topic_names_of_seven_four, crates/rpc/src/topic_naming.rs::tests::the_run_time_specification_beats_the_annotation, crates/rpc/tests/cpp/rpc_runtime_roundtrip.cpp::check_class_form (gefahren von crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together)

Status: done — innerhalb einer Ebene gilt der Topic-Name (Annotation vor @service; Suffix zur Laufzeit vor dem Service-Namen zur Laufzeit). Für einen Service-Namen zur Laufzeit neben einem Topic-Namen aus der Annotation folgt der Code §7.4.2.3 (S. 28: Laufzeit vor Annotation); dort widersprechen sich S. 27 und S. 28. Commit 4f3b0f132d8a.

§7.4.1 Stil Request/Reply: kein

Spec: §7.4.1, S. 27 — “For the request-reply style language binding, and the following underscore shall not be captured automatically.”

Repo: crates/rpc/src/topic_naming.rs (BindingStyle, compose_topic_name); crates/rpc/src/endpoint.rs::RpcEndpointBuilder::binding_style; Rust-Laufzeit im nächsten Item; C++: runtime/cpp/include/dds/rpc/core.hpp::dds::rpc::synthesize_topic_names (BindingStyle::RequestReply); Java: runtime/java/src/main/java/org/omg/dds/rpc/TopicNames.java::resolve (leerer interfaceName lässt das Segment weg)

Tests: crates/rpc/src/topic_naming.rs::tests::the_request_reply_style_drops_the_interface_segment, crates/rpc/src/endpoint.rs::tests::the_binding_style_decides_the_topic_name, crates/rpc/tests/cpp/rpc_runtime_roundtrip.cpp::check_class_form (gefahren von crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together)

Status: done — Bildung der Namen in Rust und C++ mit Test. Für Java ist der Fall in TopicNames.resolve im Code vorhanden; ein Test mit leerem interfaceName besteht nicht. Commits 4f3b0f132d8a (Bildung), 2ea2abb7d843 (C++), 35156b3406a3 (Java).

§7.4.1 Rust-Laufzeit: Topic-Namen im Stil Request/Reply

Spec: §7.4.1, S. 27 — wie oben.

Repo: crates/rpc/src/requester.rs (Requester::with_instance_style, with_topics_style, with_options); crates/rpc/src/replier.rs (Replier::with_instance_style, with_topics_style, with_options)

Tests: crates/rpc/src/requester.rs::tests::request_reply_style_drops_the_interface_segment, crates/rpc/src/replier.rs::tests::request_reply_style_drops_the_interface_segment

Status: done — with_instance und with_topics bilden den Stil Funktionsaufruf; die Varianten *_style nehmen den Stil entgegen und lassen das Segment <interface_name> weg. Die Tests prüfen die Namen am Requester und am Replier. Commits 6834e51fdfef (Bildung), 32972ee16bdd (Test am Replier).

§7.4.2 Basic: ein Request- und ein Reply-Topic je Interface

Spec: §7.4.2, S. 27 — “The Basic Service mapping maps every interface to a request topic and a reply topic.”

Repo: crates/rpc/src/codegen.rs::build_basic_pair; crates/lang-rules/src/emit/interface_rust.rs (client_impl; ein Requester je Interface)

Tests: crates/rpc/src/codegen.rs::tests::basic_pair_topic_names, crates/rpc-rust-e2e/tests/e2e.rs::the_generated_calculator_binding_runs_every_call

Status: done — Code und Tests vorhanden. Commits b5224bd70dbb (build_basic_pair), 026f15d1df46 (Test mit erzeugter Bindung).

§7.4.2 Drei Mechanismen, gleiche Namen auf beiden Seiten

Spec: §7.4.2, S. 27 — “It provides three alternative mechanisms to specify the names of the topics. It is possible to use different mechanism at the client and server sides. However, to ensure successful end-point matching, the topic names must match.”

Repo: —

Tests: —

Status: n/a (informative) — Übersicht und Vorgabe an die Anwendung; die Mechanismen stehen in §7.4.2.1 bis §7.4.2.3.

§7.4.2 Basic: eigenes Paar von Topics je Interface der Hierarchie

Spec: §7.4.2, S. 27 — “In case of an interface inheritance hierarchy, including multiple inheritance, each interface in the hierarchy shall be mapped to its own pair of request and reply topics.”

Repo: crates/lang-rules/src/emit/interface_rust.rs (client_impl: ein Feld mit dem Client der Basis je Basis; ein Dispatcher je Ebene); crates/lang-rules/src/emit/interface_cpp.rs::support_class (Namen je Interface)

Tests: crates/rpc-rust-e2e/tests/e2e.rs::a_derived_client_reaches_an_inherited_operation_through_its_base_field

Status: done — Code und Test vorhanden. Commit 026f15d1df46.

§7.4.2.1 Default Topic Names

Spec: §7.4.2.1, S. 27 — “The default topic names are synthesized using the rules defined in sub clause 7.4.1 Rules for Synthesizing DDS Topic Names.”

Repo: crates/rpc/src/topic_naming.rs::ServiceTopicNames::new; crates/rpc/src/service_mapping.rs::ServiceDef::topic_names; crates/lang-rules/src/emit/interface_cpp.rs::support_class

Tests: crates/rpc/src/topic_naming.rs::tests::service_topic_names_pair, crates/lang-rules/tests/interface_bindings.rs::cpp_carries_the_topic_names_of_seven_four

Status: done — Code und Tests vorhanden. Commit 4f3b0f132d8a.

§7.4.2.2 @DDSRequestTopic und @DDSReplyTopic an Interfaces

Spec: §7.4.2.2, S. 27 — “Interfaces and the request/reply types may be annotated to specify the names of the request and reply topics. @DDSRequestTopic and @DDSReplyTopic annotations are pre-defined for this purpose.”

Repo: crates/rpc/src/annotations.rs::lower_single; crates/rpc/src/service_mapping.rs::ServiceDef (request_topic, reply_topic); crates/lang-rules/src/adapter/interface.rs::service (annotation_string)

Tests: crates/rpc/src/annotations.rs::tests::dds_request_and_reply_topics_lower_and_resolve, crates/rpc/src/service_mapping.rs::tests::the_topic_annotations_and_the_run_time_layer_have_their_order, crates/lang-rules/tests/interface_bindings.rs::cpp_carries_the_topic_names_of_seven_four

Status: done — an Interfaces gelesen; an den Typen eines Paars und als vordefinierte Annotationen in den beiden folgenden Items. Commit 4f3b0f132d8a.

§7.4.2.2 Annotationen an den Typen eines Paars

Spec: §7.4.2.2, S. 27 — wie oben.

Repo: crates/rpc/src/type_pair.rs::lower_type_pairs (liest @DDSRequestTopic und @DDSReplyTopic an den Typen, §7.3.1.4)

Tests: crates/rpc/src/type_pair.rs::tests::the_topic_annotations_on_the_types_name_the_topics

Status: done — Code und Test vorhanden. Commit 1e28b13546c1.

§7.4.2.2 DDSRequestTopic und DDSReplyTopic vordefiniert

Spec: §7.4.2.2, S. 27 — “module dds { module rpc { @Annotation local interface DDSRequestTopic { attribute String name; }; @Annotation local interface DDSReplyTopic { attribute String name; }; }; };”

Repo: crates/ast/src/node/annotation.rs (BUILTIN_ANNOTATIONS: DDSRequestTopic, DDSReplyTopic); crates/rpc/src/annotations.rs::lower_single

Tests: crates/rpc/src/annotations.rs::tests::the_spec_annotations_need_no_declaration, crates/rpc/src/annotations.rs::tests::dds_request_and_reply_topics_lower_and_resolve

Status: done — eine Datei verwendet beide Annotationen ohne Deklaration. Sie sind Built-in-Annotationen des Frontends; die IDL-Deklaration der Spec (module dds { module rpc { @Annotation local interface … } }) wird nicht als IDL-Text angeboten. Gelesen wird nach dem letzten Namensteil; neben name = "…" gilt auch die Kurzform ohne Namen. Ein Aufruf mit vollständigem Namen (@dds::rpc::DDSRequestTopic) ist nicht geprüft. Commit 6c7f585a36ee.

§7.4.2.2 XTypes in der Implementierung nicht nötig

Spec: §7.4.2.2, S. 27 — “Note that support for [DDS-XTypes] in the underlying DDS implementation is not required to interpret the annotations. These annotations simply control the generated DDS wrapper code.”

Repo: —

Tests: —

Status: n/a (informative) — Hinweis.

§7.4.2.3 Topic-Namen zur Laufzeit über die Params-Klassen

Spec: §7.4.2.3, S. 28 — “DDS Topic names may also be specified at run-time. The ServiceParams, ClientParams, RequesterParams, and ReplierParams classes […] provide functions to specify the service name and the topic name suffix. When used as such, the rules defined in 7.4.1 Rules for Synthesizing DDS Topic Names apply.”

Repo: crates/rpc/src/topic_naming.rs::TopicNameOverrides (service_name, request_suffix, reply_suffix), weitergegeben über AnnotatedTopics an Requester::with_topics und Replier::with_topics; crates/rpc/src/endpoint.rs::RpcEndpointBuilder::topic_name_overrides; C++ und Java im nächsten Item

Tests: crates/rpc/src/topic_naming.rs::tests::a_user_supplied_suffix_replaces_the_whole_tail, crates/rpc/src/endpoint.rs::tests::the_run_time_service_name_reaches_the_endpoints

Status: done — Rust: Service-Name und Suffix zur Laufzeit mit den Regeln aus §7.4.1; C++ und Java im Item „Params-Klassen in C++ und Java“. Commits 4f3b0f132d8a, 77bb7cba7e6d.

§7.4.2.3 Params-Klassen in C++ und Java

Spec: §7.4.2.3, S. 28 — wie oben.

Repo: C++: runtime/cpp/include/dds/rpc.hpp (EndpointParams mit service_name, request_topic_name_suffix, reply_topic_name_suffix; RequesterParams, ReplierParams, ServiceParams, ClientParams; synthesize_topic_names); Java: runtime/java/src/main/java/org/omg/dds/rpc/ (RequesterParams, ReplierParams mit serviceName, requestTopicNameSuffix, replyTopicNameSuffix; TopicNames)

Tests: crates/rpc/tests/cpp/rpc_runtime_roundtrip.cpp::check_class_form (gefahren von crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together), crates/rpc/tests/java/FunctionCallRoundtrip.java (TopicNames.of(named); gefahren von crates/rpc/tests/java_rpc_runtime.rs)

Status: done — die Params-Klassen nehmen Service-Name und Suffix auf und bilden die Namen nach §7.4.1. ServiceParams und ClientParams stehen in der Spec nur in der C++-Bindung (§7.11.1.5); Java hat sie nicht. Commits 2ea2abb7d843 (C++), 35156b3406a3 (Java).

§7.4.2.3 Vorrang: Laufzeit, Annotation, Vorgabe

Spec: §7.4.2.3, S. 28 — “When more than one method of specifying topic names is used, the run-time specification shall take precedence over the IDL annotations and the default mechanism in that order.”

Repo: crates/rpc/src/topic_naming.rs::ServiceTopicNames::one; C++: runtime/cpp/include/dds/rpc/core.hpp::dds::rpc::synthesize_topic_names; Java: runtime/java/src/main/java/org/omg/dds/rpc/TopicNames.java::resolve

Tests: crates/rpc/src/topic_naming.rs::tests::the_run_time_specification_beats_the_annotation, crates/rpc/src/service_mapping.rs::tests::the_topic_annotations_and_the_run_time_layer_have_their_order, crates/rpc/tests/cpp/rpc_runtime_roundtrip.cpp::check_class_form (gefahren von crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together)

Status: done — Code und Tests vorhanden. Commits 4f3b0f132d8a, 2ea2abb7d843 (C++), 35156b3406a3 (Java).

§7.4.3 Enhanced: Aliase in der Discovery angekündigt

Spec: §7.4.3, S. 28 — “To support single and multiple inheritance of interfaces, the Enhanced Service mapping introduces a notion called “topic aliases.” […] Topic aliases are announced during the endpoint discovery protocol using either of the PublicationBuiltinTopicDataExt and SubscriptionBuiltinTopicDataExt structures described in 7.6.2.1”.

Repo: crates/rpc/src/topic_naming.rs::ServiceTopicNames::aliases; crates/rpc/src/requester.rs und crates/rpc/src/replier.rs (with_options tragen topic_aliases in RpcDiscoveryExt ein); crates/rpc/src/endpoint.rs::RpcEndpointBuilder; crates/rtps/src/publication_data.rs (topic_aliases, Codec von PID_TOPIC_ALIASES); crates/dcps (Zuordnung nach Alias, Funktionen in crates/discovery); C++: runtime/cpp/include/dds/rpc.hpp (topic_aliases) und runtime/cpp/include/dds/rpc/zerodds.hpp

Tests: crates/rpc/src/endpoint.rs::tests::the_parent_interfaces_are_announced_as_topic_aliases, crates/rpc/src/topic_naming.rs::tests::the_request_reply_style_has_no_aliases_for_the_bases_either, crates/rpc-rust-e2e/tests/evolution_styles_discovery.rs::the_runtime_announces_aliases_the_instance_name_and_the_related_keys, crates/rtps/src/publication_data.rs::tests::rpc_discovery_pids_roundtrip, crates/rtps/src/publication_data.rs::tests::a_discovery_string_beyond_the_bound_is_refused, crates/dcps/tests/topic_alias_matching.rs::a_reader_on_an_alias_matches_the_writer_over_the_wire, crates/rpc/tests/cpp/rpc_runtime_roundtrip.cpp (Prüfung request_reader.aliases.size() == 1; gefahren von crates/rpc/tests/cpp_rpc_runtime.rs)

Status: done — Rust, C++ und Java kündigen die Aliase an, crates/dcps ordnet nach Alias zu, und crates/rtps lehnt einen Alias über string<256> ab. In Java setzt ReplierParams.parents (und RequesterParams.parents) die Basis-Interfaces; TopicNames bildet daraus je Basis einen Alias (9993349aff89, Test RpcInheritanceTest.java::specOperations, RpcDiscoveryTest.java::aTopicCorrespondsByNameOrByAlias). Ein Client einer Basis erreicht einen abgeleiteten Dienst über den Alias-Treffer, obwohl die Typnamen der Request- und Reply-Typen verschieden sind: die Topics der Enhanced-Abbildung kündigen jetzt die TypeInformation ihrer Typen an (lang-rules erzeugt die CompleteTypeObject von Request, Reply, In, Out, Result, Exceptions und RemoteExceptionCode_t: a2bc3b857739; DomainParticipant::create_topic_with_type_information in crates/dcps; Requester und Replier rufen sie auf, wenn die erzeugten Optionen die Objekte tragen). Test: crates/rpc-rust-e2e/tests/enhanced_type_information.rs::base_and_derived::a_base_client_calls_a_derived_service (zwei Participants; auf dem Linux-Testhost grün; ohne die Objekte endet derselbe Aufruf mit ServiceNotMatched, gemessen mit einem Kontrolllauf). Die Rust-Laufzeit trägt die Typinformation; C++ und Java kündigen keine an (siehe die Items zu §7.5.1.2.6 und §7.7.2.5). Commits e305669e2c42 (Rust), 17a3aef74360 (C++), bdf9ab1e6caa (Zuordnung nach Alias in crates/dcps), ae5fededca89 (Grenze in crates/rtps), 32972ee16bdd und 414e077c527d (Tests).

§7.4.3 Enhanced: Java kündigt die Aliase der Params an

Spec: §7.4.3, S. 28 — “To support single and multiple inheritance of interfaces, the Enhanced Service mapping introduces a notion called “topic aliases.” […] Topic aliases are announced during the endpoint discovery protocol using either of the PublicationBuiltinTopicDataExt and SubscriptionBuiltinTopicDataExt structures described in 7.6.2.1”.

Repo: —

Tests: crates/rpc-rust-e2e/tests/java_peer.rs::a_java_client_calls_a_rust_service, crates/rpc-rust-e2e/tests/java_peer.rs::a_rust_client_calls_a_java_service, crates/rpc-rust-e2e/tests/java_peer.rs::a_java_client_of_the_base_calls_a_rust_service_of_the_derived_interface, crates/rpc-rust-e2e/tests/java_peer.rs::a_rust_client_of_the_base_calls_a_java_service_of_the_derived_interface

Status: done — RequesterParams.parents und ReplierParams.parents nehmen die Basis-Interfaces; TopicNames.resolve bildet je Basis einen Alias (nicht unter dem Stil Request/Reply und nicht bei einem ganzen Topic-Namen, wie in Rust), und RequesterImpl und ReplierImpl melden sie über DataWriter.announce und DataReader.announce (ZeroDdsParticipant → DataWriterImpl.setRpcDiscovery, PID 0x0082; 9993349aff89, f65fb3965b5e). Tests: crates/rpc/tests/java/RpcInheritanceTest.java::specOperations (Namen und Aliase), RpcDiscoveryTest.java::theThreeParametersTravelWithTheEndpoint (PID 0x0082 auf der Leitung). Die erzeugte Java-Bindung der Enhanced-Abbildung setzt parents für ein abgeleitetes Interface (400433a9d00a, geprüft an CalcSupport mit Calc : Base2 in EnhancedRuntimeChecks.support(), c9c4e86a881e). Gemessen: ein Java-Client gegen einen Rust-Dienst und ein Rust-Client gegen einen Java-Dienst über RTPS, beide mit der Ankündigung der Aliase und der TypeInformation (dbb935492284). Die Java-PSM paart die Endpunkte der Enhanced-Abbildung über die Aliase der Gegenstelle (RpcDiscovery.topicsCorrespond) und nach der Zuweisbarkeit der angekündigten TypeInformation (XTypes 1.3 §7.6.3.4.2; RawTypeSupport.matchesByTypeInformation, org.zerodds.rtps.TypeConsistency, org.zerodds.typelookup.CompleteTypes, 2d0f809c6e2). Objekte der Gegenstelle holt sie mit getTypes von deren TypeLookup-Dienst; die Java-Beschreibung trägt auch die MINIMAL-Objekte, nach denen ein Rust-Peer fragt (9b1608508c5), und ein Reader eines beschriebenen Typs kündigt ALLOW_TYPE_COERCION an (d67a980f80b). Gemessen über RTPS gegen Rust-Peers (Linux-Testhost): ein Java-Client von Base2 ruft einen Rust-Dienst von Derived2, ein Rust-Client von Base2 einen Java-Dienst von Derived2; beide Zellen schlugen auf 78f243b596f, vor der Paarung nach Zuweisbarkeit, fehl.

§7.4.3 Enhanced: genau ein Request- und ein Reply-Topic je Interface

Spec: §7.4.3, S. 28 — “The Enhanced Service Mapping shall map an interface to exactly one request topic and a reply topic. The names of the topics are obtained using the rules defined in 7.4.1 Rules for Synthesizing DDS Topic Names.”

Repo: crates/rpc/src/codegen.rs::build_enhanced_service (request_topic, reply_topic); crates/rpc/src/endpoint_options.rs::RpcMapping::Enhanced; Requester::with_options und Replier::with_options (crates/rpc/src/requester.rs, crates/rpc/src/replier.rs)

Tests: crates/rpc/src/codegen.rs::tests::enhanced_service_has_one_topic_pair, crates/rpc-rust-e2e/tests/enhanced_e2e.rs::an_enhanced_call_is_answered_through_the_related_sample_identity

Status: done — die Enhanced-Abbildung bildet ein Paar von Topics je Interface; die Laufzeit in Rust benutzt es (RpcMapping::Enhanced). C++ und Java: Commits 51bb6973e062 und 2cb2bcbe4eca. Commits 0edbbcf11324 (Abbildung), e305669e2c42 (Laufzeit in Rust).

§7.4.3 Enhanced: Aliase je Basis nach §7.4.1

Spec: §7.4.3, S. 28 — “In case of single and multiple inheritance, the request and reply topics shall additionally have topic-aliases, which are obtained using the rules in sub clause 7.4.1 for each parent interface.”

Repo: crates/rpc/src/topic_naming.rs::ServiceTopicNames::aliases; crates/rpc/src/service_mapping.rs::ServiceDef::bases; crates/lang-rules/src/adapter/interface.rs::Service::topic_aliases

Tests: crates/rpc/src/topic_naming.rs::tests::every_parent_interface_contributes_one_alias, crates/rpc/tests/language_binding_agreement.rs::the_published_table_comes_out_of_the_idl

Status: done — Aliase entstehen für die direkten Basen; ob „each parent interface“ auch Basen der Basen meint, sagt die Spec nicht. Commit 4f3b0f132d8a.

§7.4.3 Beispiel der Hierarchie Calculator

Spec: §7.4.3, S. 28–29 — Tabelle mit Topic-Namen und Aliasen für Calculator : Adder, Subtractor (“Non-normative example”).

Repo: —

Tests: —

Status: n/a (informative) — Beispiel.

§7.4.3 Stil Request/Reply: kein Name des Interface

Spec: §7.4.3, S. 29 — “For the request-reply style language binding, the interfaces name shall not be annexed automatically.”

Repo: crates/rpc/src/topic_naming.rs::ServiceTopicNames::aliases (für den Stil Request/Reply keine Aliase); C++: runtime/cpp/include/dds/rpc.hpp (topic_aliases)

Tests: crates/rpc/src/topic_naming.rs::tests::the_request_reply_style_drops_the_interface_segment (ohne Basen; Aliasliste leer)

Status: done — der Stil Request/Reply bildet keinen Namen mit dem Interface und keine Aliase; die Rust-Laufzeit nimmt den Stil entgegen (Item zu §7.4.1). Der Test übergibt keine Basen. Commits 4f3b0f132d8a, 6834e51fdfef.

§7.4.3.1 Default Topic Names (Enhanced)

Spec: §7.4.3.1, S. 29 — “The default topic names are synthesized as described above.”

Repo: crates/rpc/src/topic_naming.rs::ServiceTopicNames::synthesize; crates/rpc/src/codegen.rs::build_enhanced_service

Tests: crates/rpc/src/codegen.rs::tests::enhanced_service_has_one_topic_pair, crates/rpc/src/topic_naming.rs::tests::the_default_name_carries_the_service_segment

Status: done — Code und Tests vorhanden. Commits 4f3b0f132d8a, 0edbbcf11324.

§7.4.3.2 Annotationen für die Namen (Enhanced)

Spec: §7.4.3.2, S. 29 — “The same built-in @DDSRequestTopic and @DDSReplyTopic annotations defined in the Basic Service Mapping may be used for this purpose.”

Repo: crates/rpc/src/service_mapping.rs::ServiceDef (request_topic, reply_topic); crates/rpc/src/type_pair.rs::lower_type_pairs

Tests: crates/rpc/src/topic_naming.rs::tests::an_annotation_gives_the_whole_name_and_no_alias, crates/rpc/src/type_pair.rs::tests::the_topic_annotations_on_the_types_name_the_topics

Status: done — die Annotationen wirken unabhängig von der Abbildung (Items zu §7.4.2.2). Commits 4f3b0f132d8a, 1e28b13546c1.

§7.4.3.3 Topic-Namen zur Laufzeit (Enhanced)

Spec: §7.4.3.3, S. 29 — gleicher Wortlaut wie §7.4.2.3, einschließlich “the run-time specification shall take precedence over the IDL annotations and the default mechanism in that order.”

Repo: crates/rpc/src/topic_naming.rs::TopicNameOverrides; crates/rpc/src/endpoint.rs::RpcEndpointBuilder::topic_name_overrides; C++ und Java: Params-Klassen (Item zu §7.4.2.3)

Tests: crates/rpc/src/topic_naming.rs::tests::the_run_time_specification_beats_the_annotation, crates/rpc/src/endpoint.rs::tests::the_run_time_service_name_reaches_the_endpoints

Status: done — Code und Tests vorhanden. Commits 4f3b0f132d8a, 0edbbcf11324.


§7.5 Mapping Service Specification to DDS Topics Types

§7.5 Topic-Typen aus der Definition des Interface

Spec: §7.5, S. 30 — “The request and reply DDS Topic types shall be synthesized from the interface definition.”

Repo: crates/rpc/src/codegen.rs::build_basic_pair, crates/rpc/src/codegen.rs::build_enhanced_service; crates/lang-rules/src/emit/interface_cpp.rs::declare; crates/lang-rules/src/emit/interface_java.rs; crates/lang-rules/src/emit/interface_rust.rs::declare

Tests: crates/lang-rules/tests/interface_bindings.rs::cpp_declares_the_topic_types_of_seven_five, crates/rpc/tests/language_binding_agreement.rs::both_readings_of_seven_five_produce_the_same_sample_structure

Status: done — die Typen werden synthetisiert, und die Topics der Rust-Laufzeit tragen sie unter ihren Namen (nächstes Item). Commits ad892a10764a (Generatoren), e305669e2c42 (Laufzeit in Rust).

§7.5 Typ und Form der Samples auf der Leitung

Spec: §7.5, S. 30 — wie oben; §7.5.1.1.6 und §7.5.1.1.7 legen ${interfaceName}_Request und ${interfaceName}_Reply als Typen der Topics fest.

Repo: crates/rpc/src/requester.rs und crates/rpc/src/replier.rs (create_topic_with_type_name mit ${I}_Request und ${I}_Reply; Requester::request_type_name); crates/rpc/src/wire_codec.rs (encode_request_frame: Auffüllung auf 4 vor dem Call; ERROR_REPLY_DATA); C++: runtime/cpp/include/dds/rpc.hpp (Requester und Replier übergeben dds_type_traits<T>::type_name()), runtime/cpp/include/dds/rpc/zerodds.hpp

Tests: crates/rpc-rust-e2e/tests/enhanced_e2e.rs::the_topics_are_announced_with_the_interface_type_names, crates/rpc/src/wire_codec.rs::tests::the_call_union_starts_on_a_4_octet_boundary, crates/rpc/src/wire_codec.rs::tests::the_error_reply_data_is_the_default_case_of_the_union, crates/rpc/tests/cpp/rpc_runtime_roundtrip.cpp (angekündigte Typnamen robot::Calculator_Request und _Reply; gefahren von crates/rpc/tests/cpp_rpc_runtime.rs)

Status: done — die Topics melden ${interfaceName}_Request und ${interfaceName}_Reply als Typnamen; ein Sample ist der Header, die Auffüllung auf 4 Oktette und die Kodierung von ${I}_Call bzw. ${I}_Return; eine Antwort mit Fehlercode trägt den default-Fall der Return-Union. Die Rust-Laufzeit schreibt die Oktette dieser Strukturen über RawBytes; die erzeugten Rust-Strukturen ${I}_Request und ${I}_Reply sind keine Typen eines Topics der Laufzeit, ihre Kodierung ergibt dieselben Oktette (Spalten-Test im Item zur Kodierung). Commits e305669e2c42 (Rust), 208e7e0b25c3 (C++).

§7.5.1.1 Basic: Typen für DDS 1.3 ohne XTypes

Spec: §7.5.1.1, S. 30 — “The Basic Service Mapping maps interfaces to data-types that can be used by DDS version 1.3 compliant implementations, which may lack support for the [DDS-XTypes] specification.”

Repo: crates/lang-rules/src/emit/interface_cpp.rs::declare (Strukturen und Unions ohne Annotationen von XTypes)

Tests: crates/lang-rules/tests/interface_bindings.rs::cpp_declares_the_topic_types_of_seven_five

Status: done — die Typen nutzen nichts aus XTypes; die Kodierung ist klassisches CDR (nächstes Item). Commit ad892a10764a.

§7.5.1.1 Kodierung der Samples: klassisches CDR und XCDR2

Spec: §7.5.1.1, S. 30 — wie oben.

Repo: crates/rpc/src/endpoint_options.rs (WireEncoding, Vorgabe Xcdr1; RpcEndpointOptions); crates/lang-rules/src/emit/interface_rust.rs (rpc_layout_key_xcdr1, rpc_layout_key); C++: runtime/cpp/include/dds/rpc.hpp (WireEncoding); Java: runtime/java/src/main/java/org/omg/dds/rpc/WireEncoding.java

Tests: crates/rpc/src/endpoint_options.rs::tests::the_defaults_are_the_spec_readings, crates/rpc-rust-e2e/tests/wire_bytes_match_columns.rs::the_rust_and_cpp_columns_put_eight_octet_members_where_the_same_octets, crates/rpc-rust-e2e/tests/wire_bytes_match_columns.rs::the_rust_and_java_columns_put_eight_octet_members_where_the_same_octets, crates/rpc-rust-e2e/tests/xcdr1_nested.rs::an_appendable_member_has_no_dheader_under_xcdr1, crates/rpc-rust-e2e/tests/xcdr1_nested.rs::xcdr2_frames_the_same_value_differently

Status: done — die Spec nennt für die Basic-Abbildung nur „DDS 1.3 ohne XTypes“. Vorgabe in allen drei Laufzeiten ist klassisches CDR (XCDR1; ein Writer bietet nur diese Darstellung an); XCDR2 ist eine benannte Einstellung. Die Enhanced-Abbildung ist immer XCDR2. Die Spalten für Rust, C++ und Java setzen Member von 8 Oktetten an dieselben Stellen (Test), auch verschachtelte @appendable/@mutable-Member. Gegen einen fremden Peer ist das in diesem Audit nicht geprüft. Commits c5285c57fad2 (Rust), ec3707125a9b (C++), 80df19b642fc (Java), 87cf9c7d0b26 (verschachtelte Member), 77ded59f712c (Test der Spalten).

§7.5.1.1.1 GUID_t, SequenceNumber_t und SampleIdentity

Spec: §7.5.1.1.1, S. 30 — module dds { typedef octet GuidPrefix_t[12]; struct EntityId_t { octet entityKey[3]; octet entityKind; }; struct GUID_t { GuidPrefix_t guidPrefix; EntityId_t entityId; }; struct SequenceNumber_t { long high; unsigned long low; }; struct SampleIdentity { GUID_t writer_guid; SequenceNumber_t sequence_number; }; ...

Repo: crates/rpc/src/common_types.rs::SampleIdentity (GUID als 16 Oktette, Folgenummer als high/low auf der Leitung, encode_sample_identity); runtime/cpp/include/dds/rpc.hpp::dds::SampleIdentity und dds::SequenceNumber_t (high, low; Member sequence_number); runtime/java/src/main/java/org/omg/dds/rpc/SampleIdentity.java

Tests: crates/rpc/src/common_types.rs::tests::xcdr2_layout_sample_identity_le_is_24_bytes_no_padding, crates/rpc/src/common_types.rs::tests::sample_identity_roundtrip_le, crates/rpc/tests/cpp_rpc_runtime.rs::the_two_headers_take_the_same_octets_in_both_columns

Status: done — die Oktette stimmen in Rust, C++ und Java überein; dds::SampleIdentity in C++ hat das Member sequence_number vom Typ dds::SequenceNumber_t mit high und low. Commit d750a045b9fe.

§7.5.1.1.1 UnknownOperation, UnknownException, UnusedMember

Spec: §7.5.1.1.1, S. 31 — “typedef octet UnknownOperation; typedef octet UnknownException; typedef octet UnusedMember;”

Repo: crates/rpc/src/common_types.rs (UnusedMember, UnknownOperation, UnknownException); runtime/cpp/include/dds/rpc.hpp (UnusedMember, UnknownOperation, UnknownException); runtime/java/src/main/java/org/omg/dds/rpc/ (UnusedMember.java, UnknownOperation.java, UnknownException.java)

Tests: crates/rpc/tests/language_binding_agreement.rs::the_common_types_and_member_names_are_spelled_once

Status: done — Code und Test vorhanden. Commit ad892a10764a.

§7.5.1.1.1 RemoteExceptionCode_t mit sechs Werten

Spec: §7.5.1.1.1, S. 31 — “enum RemoteExceptionCode_t { REMOTE_EX_OK, REMOTE_EX_UNSUPPORTED, REMOTE_EX_INVALID_ARGUMENT, REMOTE_EX_OUT_OF_RESOURCES, REMOTE_EX_UNKNOWN_OPERATION, REMOTE_EX_UNKNOWN_EXCEPTION };”

Repo: crates/rpc/src/common_types.rs::RemoteExceptionCode; runtime/cpp/include/dds/rpc/base.hpp::RemoteExceptionCode_t; runtime/java/src/main/java/org/omg/dds/rpc/RemoteExceptionCode.java

Tests: crates/rpc/src/common_types.rs::tests::reply_header_roundtrip_all_codes, crates/rpc/src/common_types.rs::tests::remote_exception_code_six_is_outside_the_spec_enum, crates/rpc/src/language_binding.rs::tests::the_table_of_seven_eleven_one_three_is_the_published_one

Status: done — die sechs Werte mit 0 bis 5 in Rust, C++ und Java; ein siebter Wert besteht nicht mehr (nächstes Item). Commit 2fe2b7cdea14.

§7.5.1.1.1 Keine zusätzlichen Werte in RemoteExceptionCode_t

Spec: §7.5.1.1.1, S. 31 — wie oben.

Repo: crates/rpc/src/common_types.rs::RemoteExceptionCode::from_u32 (jeder Wert über 5 ist RpcError::UnknownExceptionCode); runtime/java/src/main/java/org/omg/dds/rpc/RemoteExceptionCode.java::fromWire (wirft RemoteUnknownExceptionError)

Tests: crates/rpc/src/common_types.rs::tests::remote_exception_code_six_is_outside_the_spec_enum, crates/rpc/src/language_binding.rs::tests::the_exception_table_covers_the_six_spec_codes

Status: done — UnknownInterface = 6 ist entfernt; der Wert 6 von der Leitung wird abgelehnt. Commit 2fe2b7cdea14.

§7.5.1.1.1 InstanceName als string<255>

Spec: §7.5.1.1.1, S. 31 — “typedef string<255> InstanceName;”

Repo: crates/rpc/src/common_types.rs::RequestHeader::instance_name, MAX_STRING_LEN (255), RequestHeader::to_cdr_le, encode_string; crates/rpc/src/wire_codec.rs::encode_request_frame

Tests: crates/rpc/src/common_types.rs::tests::request_header_roundtrip_le, crates/rpc/src/common_types.rs::tests::request_header_instance_name_over_255_is_rejected_on_encode, crates/rpc/tests/cpp/rpc_runtime_roundtrip.cpp::main (Block „InstanceName of 255 characters“; gefahren von crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together), crates/rpc/tests/java/RpcRuntimeRoundtrip.java::headerCodec (gefahren von crates/rpc/tests/java_rpc_runtime.rs::the_java_rpc_runtime_and_the_generated_services_run_together)

Status: done — Rust lehnt einen Namen über 255 beim Kodieren ab, und der Decoder lässt höchstens 256 Oktette einschließlich NUL zu. C++ (InvalidArgumentError beim Kodieren, false beim Dekodieren) und Java (IllegalArgumentException beim Kodieren, RemoteInvalidArgumentError beim Dekodieren, Grenze in Oktetten) halten dieselbe Grenze. Commits e5f4e895ad1d (Rust), ea817b7746ef (C++), 3f07ca73a620 (Java).

§7.5.1.1.1 Grenze 255 von InstanceName in C++ und Java

Spec: §7.5.1.1.1, S. 31 — wie oben.

Repo: runtime/cpp/include/dds/rpc/core.hpp::dds::rpc::detail::put_string, get_string, INSTANCE_NAME_BOUND; runtime/java/src/main/java/org/omg/dds/rpc/HeaderCodec.java (putString, getString, MAX_INSTANCE_NAME_OCTETS)

Tests: crates/rpc/tests/cpp/rpc_runtime_roundtrip.cpp::main (Block „InstanceName of 255 characters“: 255 Zeichen laufen hin und zurück, 256 werden beim Kodieren und beim Dekodieren abgelehnt; gefahren von crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together), crates/rpc/tests/java/RpcRuntimeRoundtrip.java::headerCodec (255 Oktette, 256 Oktette, 128 Zeichen mit zwei Oktetten, Längenfeld 257 und über 2^31, fehlende NUL; gefahren von crates/rpc/tests/java_rpc_runtime.rs::the_java_rpc_runtime_and_the_generated_services_run_together)

Status: done — beide Laufzeiten prüfen die Grenze 255 beim Kodieren und beim Dekodieren des RequestHeader. Commits ea817b7746ef (C++), 3f07ca73a620 (Java).

§7.5.1.1.1 RequestHeader

Spec: §7.5.1.1.1, S. 31 — “struct RequestHeader { SampleIndentity_t requestId; InstanceName instanceName; };”

Repo: crates/rpc/src/common_types.rs::RequestHeader; runtime/cpp/include/dds/rpc/base.hpp::RequestHeader; runtime/java/src/main/java/org/omg/dds/rpc/RequestHeader.java

Tests: crates/rpc/src/common_types.rs::tests::request_header_roundtrip_le, crates/rpc/src/common_types.rs::tests::xcdr2_layout_string_includes_nul, crates/rpc/tests/cpp_rpc_runtime.rs::the_two_headers_take_the_same_octets_in_both_columns, crates/rpc/tests/java_rpc_runtime.rs::the_two_headers_take_the_same_octets_in_both_columns

Status: done — Aufbau und Oktette stimmen in Rust, C++ und Java überein. Die C++-Member heißen requestId und instanceName, und beide Laufzeiten prüfen die Grenze 255 des Namens (Items „§7.5.1.1.1 — Namen der Member in C++“ und „Grenze 255 von InstanceName in C++ und Java“). Commits d750a045b9fe (Namen), ea817b7746ef (C++), 3f07ca73a620 (Java).

§7.5.1.1.1 ReplyHeader

Spec: §7.5.1.1.1, S. 31 — “struct ReplyHeader { dds::SampleIdentity relatedRequestId; dds::rpc::RemoteExceptionCode_t remoteEx; };”

Repo: crates/rpc/src/common_types.rs::ReplyHeader; runtime/cpp/include/dds/rpc/base.hpp::ReplyHeader; runtime/java/src/main/java/org/omg/dds/rpc/ReplyHeader.java

Tests: crates/rpc/src/common_types.rs::tests::reply_header_roundtrip_all_codes, crates/rpc/src/wire_codec.rs::tests::reply_header_consumed_28_bytes, crates/rpc/tests/cpp_rpc_runtime.rs::the_two_headers_take_the_same_octets_in_both_columns, crates/rpc/tests/java_rpc_runtime.rs::the_two_headers_take_the_same_octets_in_both_columns

Status: done — Aufbau und Oktette stimmen in Rust, C++ und Java überein; die C++-Member heißen relatedRequestId und remoteEx (Item „§7.5.1.1.1 — Namen der Member in C++“). Commit d750a045b9fe.

§7.5.1.1.1 — Namen der Member in C++

Spec: §7.5.1.1.1, S. 31 — requestId, instanceName, relatedRequestId, remoteEx.

Repo: runtime/cpp/include/dds/rpc.hpp (RequestHeader::requestId, instanceName; ReplyHeader::relatedRequestId, remoteEx; dds::SequenceNumber_t::high, low; dds::SampleIdentity::sequence_number); erzeugter Code mit dem Präfix cxx_ für Member, Enumeratoren und Konstanten, die in C++ reserviert sind: crates/lang-rules/src/emit/interface_cpp.rs

Tests: crates/rpc/tests/cpp/rpc_runtime_roundtrip.cpp::print_header_octets (setzt und liest requestId, instanceName, relatedRequestId, remoteEx, sequence_number.high, sequence_number.low; gefahren von crates/rpc/tests/cpp_rpc_runtime.rs::the_two_headers_take_the_same_octets_in_both_columns), crates/lang-rules/tests/cxx_prefix_members.rs::a_member_that_is_a_reserved_word_is_prefixed_by_cxx

Status: done — die Member heißen wie in der IDL der Spec (requestId, instanceName, relatedRequestId, remoteEx), sequence_number ist ein eigenes Struktur-Member mit high und low. Die Java-Laufzeit verwendet die Namen der IDL (requestId(), instanceName()). Commit d750a045b9fe.

§7.5.1.1.2 The Hashing Algorithm

Spec: §7.5.1.1.2, S. 31–32 — “long HASH (string arg) { octet md5_hash [16] ; md5_hash = compute_md5 ( arg ) ; return md5_hash[0] + 256* md5_hash[1] + 256256 md5_hash[2] + 256256256* md5_hash[3]; }”

Repo: crates/rpc/src/rpc_hash.rs::rpc_member_hash; crates/lang-rules/src/adapter/interface.rs::operation_hash

Tests: crates/rpc/src/codegen.rs::tests::the_case_label_is_the_published_hash_arithmetic, crates/rpc/src/rpc_hash.rs::tests::rpc_hash_uses_first_4_bytes_not_last, crates/rpc/src/rpc_hash.rs::tests::rpc_hash_empty_string_is_md5_empty_first_4_bytes

Status: done — die Summe kann 2^31 überschreiten; ZeroDDS liest die 32 Bit als long mit Vorzeichen. Die Spec deklariert long HASH und sagt nichts zum Überlauf. Commits 4085939c47aa (Algorithmus), 64d55a6c8f94 (Labels der Unions).

§7.5.1.1.2 Kollisionen von *_Hash nicht zu erkennen

Spec: §7.5.1.1.2, S. 32 — “Conforming implementation are not required to detect collisions of identifier names of the form *_Hash”.

Repo: —

Tests: —

Status: n/a (informative) — Erlaubnis. Die Basic-Abbildung prüft keine Kollision (in build_call_union nicht vorhanden); die Enhanced-Abbildung meldet RpcError::MemberIdCollision (§7.5.1.2.1.2, anderes Item).

§7.5.1.1.3 Regel 1: get_attribute_ und set_attribute_

Spec: §7.5.1.1.3, S. 32 — “1. Each attribute in an interface maps to a pair of IDL operations. get_attribute_ and set_attribute_ in the same interface.”

Repo: crates/lang-rules/src/adapter/interface.rs::Service::all_operations; crates/rpc/src/service_mapping.rs::lower_service (implizite Operationen je Attribut)

Tests: crates/lang-rules/tests/interface_bindings.rs::an_attribute_implies_the_operations_of_seven_five_one_one_three, crates/rpc/src/service_mapping.rs::tests::attributes_lower_into_the_implied_operations_of_seven_five_one_one_three, crates/rpc/src/service_mapping.rs::tests::a_declared_operation_colliding_with_an_implied_one_is_refused, crates/rpc-rust-e2e/tests/e2e.rs::the_generated_calculator_binding_runs_every_call

Status: done — jedes Attribut ergibt get_attribute_<name> und, wenn nicht readonly, set_attribute_<name>, in den Generatoren und im Datenmodell von crates/rpc. Commit 259cf675efdf.

§7.5.1.1.3 Namen der impliziten Operationen

Spec: §7.5.1.1.3, S. 32 — wie oben.

Repo: crates/lang-rules/src/adapter/interface.rs::Service::all_operations (get_attribute_<name>, set_attribute_<name>); crates/rpc/src/service_mapping.rs::lower_service

Tests: crates/lang-rules/tests/interface_bindings.rs::an_attribute_implies_the_operations_of_seven_five_one_one_three, crates/rpc/src/service_mapping.rs::tests::attributes_lower_into_the_implied_operations_of_seven_five_one_one_three

Status: done — der Name der Operation geht über HASH in die Labels von Call- und Return-Union ein (§7.5.1.1.6 Regel 5a); mit den Namen get_attribute_<name> und set_attribute_<name> wählt ein Peer nach der Spec dieselben Labels. Commit 259cf675efdf. ### §7.5.1.1.3 Regel 1: Konflikt mit gleichnamigen Operationen

Spec: §7.5.1.1.3, S. 32 — “It is illegal to have an interface with an attribute named and user-defined operations named get_attribute_ and set_attribute_.”

Repo: crates/rpc/src/service_mapping.rs::lower_service (Prüfung über ServiceDef::all_methods, Fehler RpcError::DuplicateMethod); crates/lang-rules/src/adapter/interface.rs::service (Fehler InterfaceError::DuplicateOperation, gilt auch für get_attribute_<name> und set_attribute_<name>)

Tests: crates/rpc/src/service_mapping.rs::tests::a_declared_operation_colliding_with_an_implied_one_is_refused, crates/lang-rules/tests/interface_bindings.rs::the_seam_refuses_an_operation_named_like_an_implied_getter, crates/lang-rules/tests/interface_bindings.rs::the_seam_refuses_an_operation_named_like_an_implied_setter

Status: done — Commits 259cf675efdf, c9f99bb02dd5. lower_service und die Stelle adapter::interface::service der Generatoren für C++, Java und Rust weisen ein Interface ab, das eine Operation mit dem Namen einer impliziten Operation deklariert. Bei einem readonly-Attribut gibt es keinen impliziten Setter, der Name set_attribute_<name> ist dort erlaubt (zweiter Test).

§7.5.1.1.3 Regel 1 — Prüfung in den Generatoren

Spec: §7.5.1.1.3, S. 32 — wie oben.

Repo: crates/lang-rules/src/adapter/interface.rs::service (InterfaceError::DuplicateOperation). crates/lang-rules ruft lower_service nicht auf und führt zerodds-rpc nicht als Abhängigkeit (Zyklus zerodds-rpc → zerodds-dcps → zerodds-lang-rules); die Prüfung steht deshalb in adapter::interface::service selbst.

Tests: crates/lang-rules/tests/interface_bindings.rs::the_seam_refuses_an_operation_named_like_an_implied_getter, crates/lang-rules/tests/interface_bindings.rs::the_seam_refuses_an_operation_named_like_an_implied_setter, crates/lang-rules/tests/interface_bindings.rs::the_seam_refuses_two_operations_of_one_name

Status: done — Commit c9f99bb02dd5. Die Generatoren erhalten für ein solches Interface den Fehler InterfaceError::DuplicateOperation und erzeugen keine zwei Fälle mit gleichem Namen und Label.

§7.5.1.1.3 Regel 2: Getter ohne Argumente mit dem Typ des Attributs

Spec: §7.5.1.1.3, S. 32 — “2. The return type of the get_attribute_ operation is the same as the attribute’s type. This operation accepts no arguments.”

Repo: crates/lang-rules/src/adapter/interface.rs::Service::all_operations; crates/rpc/src/service_mapping.rs::ServiceDef::all_methods

Tests: crates/lang-rules/tests/interface_bindings.rs::an_attribute_implies_the_operations_of_seven_five_one_one_three, crates/rpc-rust-e2e/tests/e2e.rs::the_generated_calculator_binding_runs_every_call (der erzeugte Getter get_attribute_memory() hat kein Argument und liefert i32)

Status: done — Commit 259cf675efdf.

§7.5.1.1.3 Regel 3: Setter void mit einem Argument

Spec: §7.5.1.1.3, S. 32 — “3. The return type of the set_attribute_ operation is void and it accepts an argument of the same type as that of the attribute and the name of the argument is the same as the attribute name.”

Repo: crates/lang-rules/src/adapter/interface.rs::Service::all_operations (Parameter mit attribute.name); crates/rpc/src/service_mapping.rs::ServiceDef::all_methods

Tests: crates/lang-rules/tests/interface_bindings.rs::an_attribute_implies_the_operations_of_seven_five_one_one_three, crates/rpc-rust-e2e/tests/e2e.rs::the_generated_calculator_binding_runs_every_call, crates/lang-rules/tests/interface_bindings.rs::the_implied_setter_takes_one_argument_named_like_the_attribute, crates/rpc/src/service_mapping.rs::tests::the_implied_setter_takes_one_argument_named_like_the_attribute

Status: done — Commits 259cf675efdf, 7036cde62638, 9dbad4cbd573. Rückgabe void und ein Argument prüft der erste Test; den Typ i32 erzwingt der zweite beim Übersetzen von set_attribute_memory(&self, memory: i32). Die beiden letzten Tests prüfen Name, Richtung in und Typ des Arguments gegen das Attribut und den Member gleichen Namens in Calculator_set_attribute_label_In.

§7.5.1.1.3 Regel 3 — Name des Arguments

Spec: §7.5.1.1.3, S. 32 — wie oben.

Repo: crates/lang-rules/src/adapter/interface.rs::Service::all_operations (Operation::params); crates/rpc/src/service_mapping.rs::ServiceDef::all_methods (ParamDef::name)

Tests: crates/lang-rules/tests/interface_bindings.rs::the_implied_setter_takes_one_argument_named_like_the_attribute, crates/rpc/src/service_mapping.rs::tests::the_implied_setter_takes_one_argument_named_like_the_attribute

Status: done — Commits 7036cde62638, 9dbad4cbd573. Beide Tests prüfen, dass der Parameter des Setters den Namen des Attributs trägt.

§7.5.1.1.3 Regel 4: getraises

Spec: §7.5.1.1.3, S. 32 — “4. Exception types listed in getraises, if any, are treated as if the get_attribute_ operation has the same set of exceptions listed as raises.”

Repo: crates/lang-rules/src/adapter/interface.rs::Service::all_operations und crates/rpc/src/service_mapping.rs::ServiceDef::all_methods (beide setzen raises: attribute.get_raises.clone()); lower_attribute liest get_raises

Tests: crates/lang-rules/tests/interface_bindings.rs::getraises_and_setraises_become_the_raises_of_the_implied_operations, crates/rpc/src/service_mapping.rs::tests::getraises_and_setraises_become_the_raises_of_the_implied_operations

Status: done — Commits 259cf675efdf, 7036cde62638, 9dbad4cbd573. Beide Tests enthalten ein Attribut mit getraises und setraises und prüfen, dass die implizite Operation get_attribute_<name> die Exception aus getraises in raises führt.

§7.5.1.1.3 Regel 5: setraises

Spec: §7.5.1.1.3, S. 32 — “5. Exception types listed in setraises, if any, are treated as if the set_attribute_ operation has the same set of exceptions listed as raises.”

Repo: crates/lang-rules/src/adapter/interface.rs::Service::all_operations und crates/rpc/src/service_mapping.rs::ServiceDef::all_methods (beide setzen raises: attribute.set_raises.clone()); lower_attribute liest set_raises

Tests: crates/lang-rules/tests/interface_bindings.rs::getraises_and_setraises_become_the_raises_of_the_implied_operations, crates/rpc/src/service_mapping.rs::tests::getraises_and_setraises_become_the_raises_of_the_implied_operations

Status: done — Commits 259cf675efdf, 7036cde62638, 9dbad4cbd573. Beide Tests enthalten ein Attribut mit getraises und setraises und prüfen, dass die implizite Operation set_attribute_<name> die Exception aus setraises in raises führt.

§7.5.1.1.3 Regel 4 und 5 — Result-Union der impliziten Operationen

Spec: §7.5.1.1.3, S. 32 — wie oben.

Repo: crates/lang-rules/src/emit/interface_cpp.rs::declare (Result-Union je Operation einschließlich der impliziten)

Tests: crates/lang-rules/tests/interface_bindings.rs::getraises_and_setraises_become_the_raises_of_the_implied_operations

Status: done — Commit 7036cde62638. Der Test prüft für Guarded_get_attribute_level_Result den Fall notreadable_ex ohne notwritable_ex und für Guarded_set_attribute_level_Result den Fall notwritable_ex ohne notreadable_ex. Die Prüfung von all_methods steht im Test crates/rpc/src/service_mapping.rs::tests::getraises_and_setraises_become_the_raises_of_the_implied_operations (Commit 9dbad4cbd573).

§7.5.1.1.4 Unqualifizierte Namen in den Regeln

Spec: §7.5.1.1.4, S. 32 — “In these rules the token ${interfaceName} shall be replaced with the name of the interface and the token ${operationName}_shall be replaced with the name of the operation. The substituted names are not fully qualified (i.e., any module prefixes shall be removed).”

Repo: crates/lang-rules/src/adapter/interface.rs::in_struct_name; crates/rpc/src/codegen.rs::build_call_union (svc.name, der einfache Name)

Tests: crates/lang-rules/tests/interface_bindings.rs::cpp_declares_the_topic_types_of_seven_five, crates/rpc/src/codegen.rs::tests::the_result_union_of_seven_five_one_one_five_is_built (Interface im Modul robot, Typname Calculator_add_Result)

Status: done — Commits 64d55a6c8f94, ad892a10764a.

§7.5.1.1.4 Regel 1: In-Struktur ${interfaceName}_${operationName}_In

Spec: §7.5.1.1.4, S. 32 — “1. Each operation in the interface shall map to an In structure with name “${interfaceName}_${operationName}_In.””

Repo: crates/rpc/src/codegen.rs::build_call_union; crates/lang-rules/src/adapter/interface.rs::in_struct_name

Tests: crates/rpc/src/codegen.rs::tests::basic_request_has_header_and_call_union, crates/lang-rules/tests/interface_bindings.rs::cpp_declares_the_topic_types_of_seven_five

Status: done — Commits b5224bd70dbb, ad892a10764a.

§7.5.1.1.4 Regel 2: In-Struktur im Modul des Interface

Spec: §7.5.1.1.4, S. 32 — “2. The In structure shall be defined within the same module as the original interface.”

Repo: crates/lang-rules/src/emit/interface_cpp.rs::declare (jede Deklaration mit service.module)

Tests: crates/lang-rules/tests/interface_bindings.rs::cpp_declares_the_two_abstract_classes_of_rule_one, crates/lang-rules/tests/interface_bindings.rs::cpp_declares_the_topic_types_of_seven_five, crates/lang-rules/tests/interface_bindings.rs::the_topic_types_and_constants_stand_in_the_module_of_the_interface

Status: done — Commits b5224bd70dbb, ad892a10764a, 7036cde62638. Der Code übergibt jeder Deklaration das Modul des Interface. Der Test legt zwei Module an, dazu eine Exception in einem dritten, und prüft für C++, dass die Deklaration im Namespace ihres Interface steht und weder im globalen Namespace noch im Namespace des anderen Moduls; die Rust-Bindung legt die Items im Modul ihres Interface ab. Die Lage der Java-Klassen ist nicht geprüft; die Rust-Bindung hat keine _Hash-Konstanten.

§7.5.1.1.4 Regel 3: in- und inout-Parameter als Member

Spec: §7.5.1.1.4, S. 32 — “3. The In structure shall contain as members the in and inout parameters defined in the operation signature.”

Repo: crates/rpc/src/codegen.rs::method_in_members; crates/lang-rules/src/emit/interface_cpp.rs (request_fields)

Tests: crates/rpc/src/codegen.rs::tests::basic_request_in_params_become_case_members, crates/rpc/src/codegen.rs::tests::enhanced_inout_param_is_in_both_structures (die Enhanced-Abbildung ruft dieselbe Funktion method_in_members auf), crates/rpc-rust-e2e/tests/e2e.rs::the_generated_calculator_binding_runs_every_call (swap(inout long v) über die erzeugte Rust-Bindung)

Status: done — Commit b5224bd70dbb.

§7.5.1.1.4 Regel 3a: Reihenfolge der Parameter

Spec: §7.5.1.1.4, S. 32 — “a. The members shall appear in the same order as the parameters in the operation, starting from the left.”

Repo: crates/rpc/src/codegen.rs::method_in_members

Tests: crates/rpc/src/codegen.rs::tests::basic_request_in_params_become_case_members (Member a, dann b)

Status: done — Commit b5224bd70dbb.

§7.5.1.1.4 Regel 3b: Namen der Parameter

Spec: §7.5.1.1.4, S. 32 — “b. The names of the members shall be the same as the formal parameter names.”

Repo: crates/rpc/src/codegen.rs::method_in_members

Tests: crates/rpc/src/codegen.rs::tests::basic_request_in_params_become_case_members

Status: done — Commit b5224bd70dbb.

§7.5.1.1.4 Regel 3c: dummy vom Typ UnusedMember

Spec: §7.5.1.1.4, S. 32 — “c. If an operation has no in and inout parameters the resulting structure shall contain a single member of type UnusedMember and name “dummy.””

Repo: crates/rpc/src/codegen.rs::method_in_members (DUMMY_MEMBER); crates/lang-rules/src/emit/interface_cpp.rs (request_fields)

Tests: crates/rpc/src/codegen.rs::tests::an_empty_in_or_out_carries_the_dummy_member, crates/lang-rules/tests/interface_bindings.rs::cpp_declares_the_topic_types_of_seven_five

Status: done — Commit 64d55a6c8f94.

§7.5.1.1.5 Out-Struktur und Result-Union je Operation

Spec: §7.5.1.1.5, S. 33 — “Each operation in the interface shall map to an Out structure and a Result union.”

Repo: crates/rpc/src/codegen.rs (method_out_members, build_result_union); crates/lang-rules/src/emit/interface_cpp.rs (reply_fields, result_union_of)

Tests: crates/rpc/src/codegen.rs::tests::the_result_union_of_seven_five_one_one_five_is_built, crates/rpc/src/codegen.rs::tests::basic_reply_excludes_oneway_methods, crates/lang-rules/tests/interface_bindings.rs::cpp_declares_the_topic_types_of_seven_five

Status: done — Commits 64d55a6c8f94, ad892a10764a. Eine oneway-Operation, die die Grammatik von §7.3.1.1 nicht kennt (lower_service weist sie ab), erhält weder Out-Struktur noch Result-Union und keinen Fall in der Return-Union (Item zu Produktion (87)).

§7.5.1.1.5 Out Regel 1: Name ${interfaceName}_${operationName}_Out

Spec: §7.5.1.1.5, S. 33 — “1. The name of the Out structure shall be “${interfaceName}_${operationName}_Out.””

Repo: crates/rpc/src/codegen.rs::build_result_union (out_type_name); crates/lang-rules/src/adapter/interface.rs::out_struct_name

Tests: crates/rpc/src/codegen.rs::tests::the_result_union_of_seven_five_one_one_five_is_built, crates/rpc/tests/language_binding_agreement.rs::both_readings_of_seven_five_produce_the_same_sample_structure

Status: done — Commits 64d55a6c8f94, ad892a10764a.

§7.5.1.1.5 Out Regel 2: im Modul des Interface

Spec: §7.5.1.1.5, S. 33 — “2. The Out structure shall be defined within the same module as the original interface.”

Repo: crates/lang-rules/src/emit/interface_cpp.rs::declare

Tests: crates/lang-rules/tests/interface_bindings.rs::cpp_declares_the_topic_types_of_seven_five, crates/lang-rules/tests/interface_bindings.rs::the_topic_types_and_constants_stand_in_the_module_of_the_interface

Status: done — Commits 64d55a6c8f94, ad892a10764a, 7036cde62638. Der Code übergibt das Modul des Interface. Der Test legt zwei Module an, dazu eine Exception in einem dritten, und prüft für C++, dass die Deklaration im Namespace ihres Interface steht und weder im globalen Namespace noch im Namespace des anderen Moduls; die Rust-Bindung legt die Items im Modul ihres Interface ab. Die Lage der Java-Klassen ist nicht geprüft; die Rust-Bindung hat keine _Hash-Konstanten.

§7.5.1.1.5 Out Regel 3: out- und inout-Parameter, dazu return_

Spec: §7.5.1.1.5, S. 33 — “3. The Out structure shall contain as members the out and inout parameters defined in the operation signature. In addition it may contain a member named “return_.” a. The Out structure shall include one member for each out and inout parameter in the operation signature.”

Repo: crates/rpc/src/codegen.rs::method_out_members; crates/lang-rules/src/emit/interface_cpp.rs (reply_fields)

Tests: crates/rpc/src/codegen.rs::tests::basic_reply_return_value_is_the_last_member, crates/rpc/src/codegen.rs::tests::enhanced_inout_param_is_in_both_structures (die Enhanced-Abbildung ruft dieselbe Funktion method_out_members auf), crates/rpc-rust-e2e/tests/e2e.rs::the_generated_calculator_binding_runs_every_call

Status: done — Commit 64d55a6c8f94.

§7.5.1.1.5 Out Regel 3a.i: Reihenfolge der Parameter

Spec: §7.5.1.1.5, S. 33 — “i. The members shall appear in the same order as the parameters in the operation, starting from the left.”

Repo: crates/rpc/src/codegen.rs::method_out_members

Tests: crates/rpc/src/codegen.rs::tests::basic_reply_return_value_is_the_last_member, crates/rpc/src/codegen.rs::tests::basic_out_members_keep_the_order_of_the_parameters, crates/lang-rules/tests/interface_bindings.rs::the_out_structure_keeps_the_order_of_the_parameters

Status: done — Commits 64d55a6c8f94, 9dbad4cbd573, 7036cde62638. Der Code hält die Reihenfolge der Deklaration. Der erste Test hat mehrere out- und inout-Parameter; der zweite prüft mit mix(in long a, inout long b, out double c) und mix2(out double c, in long a, inout long b) die Reihenfolge der Member in C++ und Java (return_ zuletzt, in-Parameter nicht enthalten). Für die Rust-Bindung gibt es keinen eigenen Test der Reihenfolge mehrerer Member.

§7.5.1.1.5 Out Regel 3a.i — mehrere Parameter

Spec: §7.5.1.1.5, S. 33 — wie oben.

Repo: crates/rpc/src/codegen.rs::method_out_members; crates/lang-rules/src/emit/interface_cpp.rs (reply_fields)

Tests: crates/rpc/src/codegen.rs::tests::basic_out_members_keep_the_order_of_the_parameters, crates/lang-rules/tests/interface_bindings.rs::the_out_structure_keeps_the_order_of_the_parameters

Status: done — Commits 9dbad4cbd573, 7036cde62638. Die Tests prüfen die Reihenfolge mehrerer out- und inout-Parameter in der Out-Struktur (siehe Item „Out Regel 3a.i: Reihenfolge der Parameter“).

§7.5.1.1.5 Out Regel 3a.ii: Namen der Parameter

Spec: §7.5.1.1.5, S. 33 — “ii. The name of the members shall be the same as the formal parameter names.”

Repo: crates/rpc/src/codegen.rs::method_out_members

Tests: crates/rpc/src/codegen.rs::tests::basic_reply_return_value_is_the_last_member (Member wrapped)

Status: done — Commit 64d55a6c8f94.

§7.5.1.1.5 Out Regel 3b: return_ als letzter Member

Spec: §7.5.1.1.5, S. 33 — “b. If the operation defines a non-void return value the Out structure shall have its last member named “return_.” The type of the “return_” member shall be the return type of the operation. In the case where the function does not define a return value this member shall not be present.”

Repo: crates/rpc/src/codegen.rs::method_out_members (RETURN_MEMBER)

Tests: crates/rpc/src/codegen.rs::tests::basic_reply_return_value_is_the_last_member, crates/lang-rules/tests/interface_bindings.rs::cpp_declares_the_topic_types_of_seven_five

Status: done — Commit 64d55a6c8f94.

§7.5.1.1.5 Out Regel 3b: return_N bei Kollision

Spec: §7.5.1.1.5, S. 33 — “If an operation has an out argument named return_ and the operation has a regular return value, the regular return value in the Out structure shall be represented as return_N member of the appropriate type where N is the first integer in the range 1 to 2^31 that avoids the collision.”

Repo: crates/rpc/src/codegen.rs::return_member_name; crates/lang-rules/src/emit/interface_cpp.rs::return_member_name, crates/lang-rules/src/emit/interface_java.rs::return_member_name, crates/lang-rules/src/emit/interface_rust.rs::return_member_name

Tests: crates/rpc/src/codegen.rs::tests::a_colliding_return_member_takes_the_first_free_number, crates/lang-rules/tests/interface_bindings.rs::a_colliding_return_member_is_numbered_in_cpp_and_java, crates/lang-rules/tests/interface_bindings.rs::a_colliding_return_member_is_numbered_in_rust

Status: done — Commits 64d55a6c8f94, 7036cde62638. Der erste Test deckt return_member_name in crates/rpc; die beiden anderen prüfen mit long f(out long return_) die Member return_ und return_1 in dieser Reihenfolge in C++, Java und Rust.

§7.5.1.1.5 Out Regel 3b: return_N — Generatoren

Spec: §7.5.1.1.5, S. 33 — wie oben.

Repo: crates/lang-rules/src/emit/interface_cpp.rs::return_member_name, crates/lang-rules/src/emit/interface_java.rs::return_member_name, crates/lang-rules/src/emit/interface_rust.rs::return_member_name

Tests: crates/lang-rules/tests/interface_bindings.rs::a_colliding_return_member_is_numbered_in_cpp_and_java, crates/lang-rules/tests/interface_bindings.rs::a_colliding_return_member_is_numbered_in_rust

Status: done — Commit 7036cde62638. Die Tests erwarten return_1 in Odd_f_Out für long f(out long return_) in C++ und Java (Text der Deklaration) und in Rust (Felder des Items).

§7.5.1.1.5 Out Regel 3c: dummy ohne Rückgabe und ohne out

Spec: §7.5.1.1.5, S. 33 — “c. If the operation has no return value, no out/inout parameters, the Out structure shall contain a single member named “dummy” of type dds::rpc::UnusedMember.”

Repo: crates/rpc/src/codegen.rs::method_out_members; crates/lang-rules/src/emit/interface_cpp.rs (reply_fields)

Tests: crates/rpc/src/codegen.rs::tests::an_empty_in_or_out_carries_the_dummy_member

Status: done — Commit 64d55a6c8f94.

§7.5.1.1.5 Result Regel 1: Name ${interfaceName}_${operationName}_Result

Spec: §7.5.1.1.5, S. 34 — “1. The Result union name shall be “${interfaceName}}_${operationName}_Result.””

Repo: crates/rpc/src/codegen.rs::build_result_union; crates/lang-rules/src/adapter/interface.rs::result_union_name

Tests: crates/rpc/src/codegen.rs::tests::the_result_union_of_seven_five_one_one_five_is_built

Status: done — Commits 64d55a6c8f94, ad892a10764a.

§7.5.1.1.5 Result Regel 2: Diskriminator long

Spec: §7.5.1.1.5, S. 34 — “2. The Result union discriminator type shall be long.”

Repo: crates/rpc/src/codegen.rs::ExceptionCase::discriminator (i32); crates/lang-rules/src/emit/interface_cpp.rs::discriminator_field (Int32)

Tests: crates/rpc/src/codegen.rs::tests::the_exception_label_hashes_the_scoped_name

Status: done — Commit 64d55a6c8f94.

§7.5.1.1.5 Result Regel 3: Fall dds::RETCODE_OK

Spec: §7.5.1.1.5, S. 34 — “3. The Result union shall have a case with label dds::RETCODE_OK which is used to represent a successful return.”

Repo: crates/rpc/src/codegen.rs::RETCODE_OK; crates/lang-rules/src/emit/interface_cpp.rs::result_union_of

Tests: crates/rpc/src/codegen.rs::tests::the_result_union_of_seven_five_one_one_five_is_built (RETCODE_OK == 0)

Status: done — Commit 64d55a6c8f94.

§7.5.1.1.5 Result Regel 3a: Member result vom Typ der Out-Struktur

Spec: §7.5.1.1.5, S. 34 — “a. This case label shall contain a single member with name “result” and type ${interfaceName}_${operationName}_Out.”

Repo: crates/rpc/src/codegen.rs::RESULT_MEMBER; crates/lang-rules/src/emit/interface_cpp.rs::result_union_of

Tests: crates/rpc/src/codegen.rs::tests::the_result_union_of_seven_five_one_one_five_is_built, crates/lang-rules/tests/interface_bindings.rs::cpp_declares_the_topic_types_of_seven_five

Status: done — Commit 64d55a6c8f94.

§7.5.1.1.5 Result Regel 4a: Konstante ${exceptionType}_Ex_Hash

Spec: §7.5.1.1.5, S. 34 — “a. A constant of type long and with name “${exceptionType}_Ex_Hash” shall be available in the same namespace as the interface is defined in.”

Repo: crates/lang-rules/src/emit/interface_cpp.rs::declare (Konstante mit service.module); crates/lang-rules/src/adapter/interface.rs::exception_hash_constant

Tests: crates/lang-rules/tests/interface_bindings.rs::cpp_declares_the_topic_types_of_seven_five, crates/rpc/src/codegen.rs::tests::the_result_union_of_seven_five_one_one_five_is_built, crates/lang-rules/tests/interface_bindings.rs::the_topic_types_and_constants_stand_in_the_module_of_the_interface

Status: done — Commits 64d55a6c8f94, 7036cde62638. Name, Typ (std::int32_t) und Vorkommen der Konstante Overflow_Ex_Hash sind getestet. Der Test legt zwei Module an, dazu eine Exception in einem dritten, und prüft für C++, dass die Deklaration im Namespace ihres Interface steht und weder im globalen Namespace noch im Namespace des anderen Moduls; die Rust-Bindung legt die Items im Modul ihres Interface ab. Die Lage der Java-Klassen ist nicht geprüft; die Rust-Bindung hat keine _Hash-Konstanten.

§7.5.1.1.5 Result Regel 4b: HASH des voll qualifizierten Namens

Spec: §7.5.1.1.5, S. 34 — “b. The value of the constant shall be the HASH of the fully qualified name of the exception type where module separator to be used is “::” (2 colons).”

Repo: crates/rpc/src/service_mapping.rs::scoped_exception_name; crates/lang-rules/src/adapter/interface.rs::exception_hash

Tests: crates/rpc/src/codegen.rs::tests::the_exception_label_hashes_the_scoped_name (MD5 von robot::Overflow), crates/rpc/tests/language_binding_agreement.rs::both_readings_of_seven_five_produce_the_same_sample_structure (exception_hash im Generator gleich dem Wert der Laufzeit)

Status: done — Commit 64d55a6c8f94. Der Name wird ohne führendes :: gebildet (robot::Overflow); das Beispiel der Spec auf S. 34 hasht "TooFast" ohne Modul.

§7.5.1.1.5 Result Regel 5: ein Fall je Exception

Spec: §7.5.1.1.5, S. 34 — “5. The union shall have a case label for each exception declared as a possible outcome of the operation.”

Repo: crates/rpc/src/codegen.rs::build_result_union

Tests: crates/rpc/src/codegen.rs::tests::the_result_union_of_seven_five_one_one_five_is_built, crates/rpc/tests/language_binding_agreement.rs::both_readings_of_seven_five_produce_the_same_sample_structure (Anzahl der Fälle gleich raises.len())

Status: done — Commit 64d55a6c8f94.

§7.5.1.1.5 Result Regel 5a: Label ${exceptionType}_Ex_Hash

Spec: §7.5.1.1.5, S. 34 — “a. The integral value of the case label shall be ${exceptionType}_Ex_Hash.”

Repo: crates/rpc/src/codegen.rs::ExceptionCase (discriminator, hash_constant)

Tests: crates/rpc/src/codegen.rs::tests::the_exception_label_hashes_the_scoped_name

Status: done — Commit 64d55a6c8f94.

§7.5.1.1.5 Result Regel 5b: Member _ex in Kleinschreibung

Spec: §7.5.1.1.5, S. 34 — “b. The case label shall contain a single member with name synthetized as the lower-case of the exception name with the suffix “_ex” added.”

Repo: crates/rpc/src/codegen.rs::build_result_union (member); crates/lang-rules/src/adapter/interface.rs::exception_member_name

Tests: crates/rpc/src/codegen.rs::tests::the_result_union_of_seven_five_one_one_five_is_built (toofast_ex)

Status: done — Commit 64d55a6c8f94.

§7.5.1.1.5 Result Regel 5c: Typ der Exception

Spec: §7.5.1.1.5, S. 34 — “c. The type associated with the case member shall be the exception type.”

Repo: crates/lang-rules/src/emit/interface_cpp.rs::result_union_of

Tests: crates/lang-rules/tests/interface_bindings.rs::cpp_declares_the_topic_types_of_seven_five (Overflow overflow_ex;)

Status: done — Commits 64d55a6c8f94, ad892a10764a.

§7.5.1.1.4 und §7.5.1.1.5 Beispiele

Spec: §7.5.1.1.4–§7.5.1.1.5, S. 32–35 — Beispiele für RobotControl (“Non-normative Example”).

Repo: —

Tests: —

Status: n/a (informative) — Beispiele.

§7.5.1.1.6 Call Regel 1: ${interfaceName}_Call im Modul des Interface

Spec: §7.5.1.1.6, S. 35 — “Each interface shall map to a Call union and a Request structure. […] 1. The Call union name shall be “${interfaceName}_Call” in the same module as the interface.”

Repo: crates/rpc/src/codegen.rs::build_call_union; crates/lang-rules/src/adapter/interface.rs::call_union_name; crates/lang-rules/src/emit/interface_cpp.rs::declare

Tests: crates/rpc/src/codegen.rs::tests::basic_request_has_header_and_call_union, crates/lang-rules/tests/interface_bindings.rs::cpp_declares_the_topic_types_of_seven_five, crates/lang-rules/tests/interface_bindings.rs::the_topic_types_and_constants_stand_in_the_module_of_the_interface

Status: done — Commits b5224bd70dbb, ad892a10764a, 7036cde62638. Der Name Calculator_Call ist getestet. Der Test legt zwei Module an, dazu eine Exception in einem dritten, und prüft für C++, dass die Deklaration im Namespace ihres Interface steht und weder im globalen Namespace noch im Namespace des anderen Moduls; die Rust-Bindung legt die Items im Modul ihres Interface ab. Die Lage der Java-Klassen ist nicht geprüft; die Rust-Bindung hat keine _Hash-Konstanten.

§7.5.1.1.6 Call Regel 2: Diskriminator long

Spec: §7.5.1.1.6, S. 35 — “2. The Call union discriminator type shall be of type long.”

Repo: crates/rpc/src/codegen.rs::CallUnionCase::discriminator (i32); crates/lang-rules/src/emit/interface_cpp.rs::discriminator_field (Int32)

Tests: crates/rpc/src/codegen.rs::tests::the_case_label_is_the_published_hash_arithmetic

Status: done — Commit 64d55a6c8f94.

§7.5.1.1.6 Call Regel 3: default mit unknownOp

Spec: §7.5.1.1.6, S. 35 — “3. The Call union shall have a default case label containing a member named “unknownOp” of type dds::rpc::UnknownOperation.”

Repo: crates/rpc/src/codegen.rs::UNKNOWN_OP_MEMBER; crates/lang-rules/src/emit/interface_cpp.rs::union_of

Tests: crates/rpc/src/codegen.rs::tests::both_unions_carry_the_default_unknown_operation_case, crates/lang-rules/tests/interface_bindings.rs::cpp_declares_the_topic_types_of_seven_five

Status: done — Commit 64d55a6c8f94.

§7.5.1.1.6 Call Regel 4: Konstante ${interfaceName}_${operationName}_Hash

Spec: §7.5.1.1.6, S. 35 — “4. For each operation in the interface, an integral constant of type long and name “$(interfaceName}_$ {operationName}_Hash” shall be present in the same module as the interface. The value of this constant is the HASH of unqualified ${operationName}.”

Repo: crates/rpc/src/codegen.rs::CallUnionCase::hash_constant; crates/lang-rules/src/emit/interface_cpp.rs::declare (hash_constant, operation_hash)

Tests: crates/rpc/src/codegen.rs::tests::the_case_labels_are_the_operation_hashes, crates/lang-rules/tests/interface_bindings.rs::cpp_declares_the_topic_types_of_seven_five, crates/lang-rules/tests/interface_bindings.rs::the_topic_types_and_constants_stand_in_the_module_of_the_interface

Status: done — Commits 64d55a6c8f94, 7036cde62638. Name, Typ (std::int32_t) und Wert (HASH des unqualifizierten Namens) sind getestet. Der Test legt zwei Module an, dazu eine Exception in einem dritten, und prüft für C++, dass die Deklaration im Namespace ihres Interface steht und weder im globalen Namespace noch im Namespace des anderen Moduls; die Rust-Bindung legt die Items im Modul ihres Interface ab. Die Lage der Java-Klassen ist nicht geprüft; die Rust-Bindung hat keine _Hash-Konstanten.

§7.5.1.1.6 Call Regel 5: ein Fall je Operation

Spec: §7.5.1.1.6, S. 35 — “5. The Call union shall have a case label for each operation in the interface.”

Repo: crates/rpc/src/codegen.rs::build_call_union (über ServiceDef::all_methods, also die impliziten Operationen der Attribute eingeschlossen)

Tests: crates/rpc/src/codegen.rs::tests::basic_request_has_header_and_call_union

Status: done — Commits b5224bd70dbb, 259cf675efdf.

§7.5.1.1.6 Call Regel 5a: Label HASH des Namens der Operation

Spec: §7.5.1.1.6, S. 35 — “a. The integral value of the case label shall be the HASH of ${operationName}.”

Repo: crates/rpc/src/codegen.rs::build_call_union (rpc_member_hash(&m.name))

Tests: crates/rpc/src/codegen.rs::tests::the_case_label_is_the_published_hash_arithmetic, crates/rpc/src/codegen.rs::tests::the_case_labels_are_the_operation_hashes

Status: done — Commit 64d55a6c8f94. ### §7.5.1.1.6 Call Regel 5b: Member mit dem Namen der Operation

Spec: §7.5.1.1.6, S. 35 — “b. The member name for the case label shall be the operation name.”

Repo: crates/rpc/src/codegen.rs::CallUnionCase::method

Tests: crates/rpc/src/codegen.rs::tests::basic_request_has_header_and_call_union

Status: done — Commit b5224bd70dbb.

§7.5.1.1.6 Call Regel 5c: Typ ${interfaceName}_${operationName}_In

Spec: §7.5.1.1.6, S. 35 — “c. The type for the case label member shall be ${interfaceName}_${operationName}_In as defined in sub clause 7.5.1.1.2 The Hashing Algorithm.”

Repo: crates/rpc/src/codegen.rs::CallUnionCase::case_type_name

Tests: crates/rpc/src/codegen.rs::tests::basic_request_has_header_and_call_union

Status: done — Commit b5224bd70dbb.

§7.5.1.1.4 bis §7.5.1.1.6 Lage der Typen und Konstanten im Modul — ohne Test

Spec: §7.5.1.1.4 Regel 2, §7.5.1.1.5 Out Regel 2 und Result Regel 4a, §7.5.1.1.6 Regel 1 und 4 — wie oben.

Repo: crates/lang-rules/src/emit/interface_cpp.rs (Namespace je Modul des Interface); crates/lang-rules/src/emit/interface_rust.rs (Rust-Modul je Modul des Interface)

Tests: crates/lang-rules/tests/interface_bindings.rs::the_topic_types_and_constants_stand_in_the_module_of_the_interface

Status: done — der Test hat zwei Module a und b und eine Exception in einem dritten Modul. Er prüft für C++, dass Svc_f_In, Svc_f_Out, Svc_f_Result, Svc_Call, Svc_Return, Svc_Request, Svc_Reply, Svc_f_Hash und Bad_Ex_Hash genau im Namespace a stehen und Other_g_In, Other_Call, Other_g_Hash genau im Namespace b. Für Rust prüft er die Lage der Strukturen und Aufzählungen im Modul des Interface; Rust erzeugt keine _Hash-Konstanten, sie sind dort nicht geprüft. Commit 7036cde62638. ### §7.5.1.1.6 Request Regel 1: ${interfaceName}_Request im Modul

Spec: §7.5.1.1.6, S. 36 — “1. The name of Request structure shall be “${interfaceName}_Request” in the same module as the interface.”

Repo: crates/rpc/src/codegen.rs::build_basic_pair (Commit 64d55a6c8f94); crates/lang-rules/src/adapter/interface.rs::request_type_name (Commit ad892a10764a)

Tests: crates/rpc/src/codegen.rs::tests::basic_pair_topic_names, crates/lang-rules/tests/interface_bindings.rs::cpp_declares_the_topic_types_of_seven_five

Status: done

§7.5.1.1.6 Request Regel 2: zwei Member

Spec: §7.5.1.1.6, S. 36 — “2. The Request structure shall have two members”.

Repo: crates/rpc/src/codegen.rs::build_basic_pair (Commit 64d55a6c8f94)

Tests: crates/rpc/src/codegen.rs::tests::basic_request_has_header_and_call_union

Status: done

§7.5.1.1.6 Request Regel 2a: header vom Typ RequestHeader

Spec: §7.5.1.1.6, S. 36 — “a. The first member of the Request structure shall be named “header” and be of type dds::rpc::RequestHeader.”

Repo: crates/rpc/src/codegen.rs::build_basic_pair (Commit 64d55a6c8f94)

Tests: crates/rpc/src/codegen.rs::tests::basic_request_has_header_and_call_union

Status: done

§7.5.1.1.6 Request Regel 2b: data vom Typ ${interfaceName}_Call

Spec: §7.5.1.1.6, S. 36 — “b. The second member of the Request structure shall be named “data” and be of type ${interfaceName}_Call.”

Repo: crates/rpc/src/codegen.rs::build_basic_pair (Commit 64d55a6c8f94)

Tests: crates/rpc/src/codegen.rs::tests::basic_request_has_header_and_call_union, crates/lang-rules/tests/interface_bindings.rs::cpp_declares_the_topic_types_of_seven_five

Status: done

§7.5.1.1.6 Beispiele

Spec: §7.5.1.1.6, S. 36–37 — RobotControl_Call und RobotControl_Request (“Non-normative Example”).

Repo: —

Tests: —

Status: n/a (informative) — Beispiele.

§7.5.1.1.7 Return Regel 1: ${interfaceName}_Return im Modul

Spec: §7.5.1.1.7, S. 37 — “Each interface shall map to a Return union and a Reply structure. […] 1. The Return union name shall be “${interfaceName}_Return” in the same module as the interface.”

Repo: crates/rpc/src/codegen.rs::build_call_union (mit reply = true; Commit 64d55a6c8f94); crates/lang-rules/src/adapter/interface.rs::return_union_name (Commit 64d55a6c8f94)

Tests: crates/rpc/src/codegen.rs::tests::basic_reply_excludes_oneway_methods, crates/lang-rules/tests/interface_bindings.rs::cpp_declares_the_topic_types_of_seven_five

Status: done

§7.5.1.1.7 Return Regel 2: Diskriminator long

Spec: §7.5.1.1.7, S. 37 — “2. The Return union discriminator type shall be of type long.”

Repo: crates/rpc/src/codegen.rs::CallUnionCase::discriminator (Commit 64d55a6c8f94)

Tests: crates/rpc/src/codegen.rs::tests::the_case_labels_are_the_operation_hashes

Status: done

§7.5.1.1.7 Return Regel 3: default mit unknownOp

Spec: §7.5.1.1.7, S. 37 — “3. The Return union shall have a default case label containing a member named “unknownOp” of type dds::rpc::UnknownOperation.”

Repo: crates/rpc/src/codegen.rs::build_call_union (default_member, UNKNOWN_OP_MEMBER; Commit 64d55a6c8f94)

Tests: crates/rpc/src/codegen.rs::tests::both_unions_carry_the_default_unknown_operation_case

Status: done

§7.5.1.1.7 Return Regel 4a: Konstante ${interfaceName}_${operationName}_Hash

Spec: §7.5.1.1.7, S. 37 — “a. A constant of type long and with name “${interfaceName}_${operationName}_Hash” shall be available in the same namespace as the interface is defined in.”

Repo: crates/lang-rules/src/emit/interface_cpp.rs::declare (hash_constant, eine Konstante je Operation für beide Unions; Commit 64d55a6c8f94)

Tests: crates/lang-rules/tests/interface_bindings.rs::cpp_declares_the_topic_types_of_seven_five

Status: done

§7.5.1.1.7 Return Regel 4b: HASH des unqualifizierten Namens

Spec: §7.5.1.1.7, S. 37 — “b. The value of the constant shall be the HASH of the name of the operation (not qualified).”

Repo: crates/lang-rules/src/adapter/interface.rs::operation_hash (Commit 64d55a6c8f94)

Tests: crates/rpc/src/codegen.rs::tests::the_case_labels_are_the_operation_hashes

Status: done

§7.5.1.1.7 Return Regel 5: ein Fall je Operation

Spec: §7.5.1.1.7, S. 37 — “5. The Return union shall have a case label for each operation in the interface”.

Repo: crates/rpc/src/codegen.rs::build_call_union (Commit 64d55a6c8f94)

Tests: crates/rpc/src/codegen.rs::tests::basic_reply_excludes_oneway_methods

Status: done — oneway-Operationen erhalten keinen Fall (Item zu Produktion (87) in §7.3.1.1).

§7.5.1.1.7 Return Regel 5a: Label ${interfaceName}_${operationName}_Hash

Spec: §7.5.1.1.7, S. 37 — “a. The integral value of the case label shall be ${interfaceName}_${operationName}_Hash as computed using the HASH algorithm of the unqualified name of the operation.”

Repo: crates/rpc/src/codegen.rs::build_call_union (Commit 64d55a6c8f94)

Tests: crates/rpc/src/codegen.rs::tests::the_case_labels_are_the_operation_hashes

Status: done

§7.5.1.1.7 Return Regel 5b: Member und Typ ${interfaceName}_${operationName}_Result

Spec: §7.5.1.1.7, S. 37 — “b. The member name for the case label shall be the operation name and the type shall be ${interfaceName}_${operationName}_Result.”

Repo: crates/rpc/src/codegen.rs::build_call_union (case_type_name; Commit 64d55a6c8f94)

Tests: crates/rpc/src/codegen.rs::tests::basic_reply_excludes_oneway_methods

Status: done

§7.5.1.1.7 Reply Regel 1: ${interfaceName}_Reply

Spec: §7.5.1.1.7, S. 38 — “1. The Reply structure name shall be “${interfaceName}_Reply,”.”

Repo: crates/rpc/src/codegen.rs::build_basic_pair (Commit 64d55a6c8f94); crates/lang-rules/src/adapter/interface.rs::reply_type_name (Commit ad892a10764a)

Tests: crates/rpc/src/codegen.rs::tests::basic_pair_topic_names

Status: done

§7.5.1.1.7 Reply Regel 2: im Modul des Interface

Spec: §7.5.1.1.7, S. 38 — “2. The Reply structure shall be defined within the same module as the original interface.”

Repo: crates/lang-rules/src/emit/interface_cpp.rs::declare (Commit ad892a10764a)

Tests: crates/lang-rules/tests/interface_bindings.rs::cpp_declares_the_topic_types_of_seven_five

Status: done

§7.5.1.1.7 Reply Regel 3: zwei Member

Spec: §7.5.1.1.7, S. 38 — “3. The Reply structure shall have two members”.

Repo: crates/rpc/src/codegen.rs::build_basic_pair (Commit 64d55a6c8f94)

Tests: crates/rpc/src/codegen.rs::tests::basic_reply_excludes_oneway_methods

Status: done

§7.5.1.1.7 Reply Regel 3a: header vom Typ ReplyHeader

Spec: §7.5.1.1.7, S. 38 — “a. The first member of the Reply structure shall be named “header” and be of type dds::rpc::ReplyHeader.”

Repo: crates/rpc/src/codegen.rs::build_basic_pair (Commit 64d55a6c8f94)

Tests: crates/lang-rules/tests/interface_bindings.rs::cpp_declares_the_topic_types_of_seven_five

Status: done

§7.5.1.1.7 Reply Regel 3b: data vom Typ ${interfaceName}_Return

Spec: §7.5.1.1.7, S. 38 — “b. The second member of the Reply type shall be named “data” and be of type ${interfaceName}_Return.”

Repo: crates/rpc/src/codegen.rs::build_basic_pair (Commit 64d55a6c8f94)

Tests: crates/rpc/src/codegen.rs::tests::basic_reply_excludes_oneway_methods, crates/lang-rules/tests/interface_bindings.rs::cpp_declares_the_topic_types_of_seven_five

Status: done

§7.5.1.1.7 Beispiele

Spec: §7.5.1.1.7, S. 37–38 — RobotControl_Return und RobotControl_Reply (“Non-normative Example”).

Repo: —

Tests: —

Status: n/a (informative) — Beispiele. Das Beispiel nennt den zweiten Member von RobotControl_Reply reply, Regel 3b data.

§7.5.1.1.8 Vererbung ändert die Typen nicht

Spec: §7.5.1.1.8, S. 38 — “Inheritance has no effect on the generated structures and unions. […] The Request and Reply types for a derived interface includes operations defined only in the derived interface.”

Repo: crates/lang-rules/src/emit/interface_cpp.rs::declare (Topic-Typen aus service.all_operations(), nur die eigenen Operationen; Commit ad892a10764a); crates/lang-rules/src/emit/interface_rust.rs::declare (Commit 7751c4065bd3)

Tests: crates/rpc-rust-e2e/tests/e2e.rs::a_derived_client_reaches_an_inherited_operation_through_its_base_field (Commit 026f15d1df46)

Status: done

§7.5.1.1.8 N Topics, N DataWriter und N DataReader

Spec: §7.5.1.1.8, S. 38 — “A DDS service that implements a derived interface uses two topics for every interface in the hierarchy. As a result, a service implementing a hierarchy of N interfaces, shall have N request topics and N reply topics. Consequently, it will necessitate N DataWriters and N DataReaders. The types and the topic names are obtained as specified in 7.4.2 Basic Service Mapping.”

Repo: crates/lang-rules/src/emit/interface_rust.rs::client_impl (ein Requester je Ebene); crates/lang-rules/src/emit/interface_rust.rs (ein Dispatcher je Ebene, jeder mit eigenem Replier; Commit 7751c4065bd3)

Tests: crates/rpc-rust-e2e/tests/e2e.rs::a_derived_client_reaches_an_inherited_operation_through_its_base_field (Commit 026f15d1df46)

Status: done

§7.5.1.1.8 Beispiel Calculator

Spec: §7.5.1.1.8, S. 38–43 — Basic-Abbildung von Calculator : Adder, Subtractor (“Non-normative Example”).

Repo: —

Tests: —

Status: n/a (informative) — Beispiel. Es weicht von den Regeln ab: die Result-Unions haben default: dds::rpc::UnknownException unknownEx und das Label dds::rpc::REMOTE_EX_OK (Regel 3 nennt dds::RETCODE_OK), Calculator_off_Result ist als struct ... switch (long) geschrieben, und Calculator_Reply hat einen header vom Typ RequestHeader.

§7.5.1.2 Enhanced-Abbildung

Spec: §7.5.1.2, S. 43 — “To accurately capture the semantics of the method call invocation and return, this specification defines additional built-in annotations. […] The Enhanced Service Mapping uses the [DDS-XTypes] type system in addition to the annotations defined in 7.5.1.2.1”.

Repo: crates/rpc/src/codegen.rs::build_enhanced_service und build_enhanced_service_with (Commit 0edbbcf11324); Topic-Typen und Codecs in crates/lang-rules/src/emit/interface_rust/enhanced.rs (Commit 41b3b02f7a20), crates/lang-rules/src/emit/interface_cpp/enhanced.rs, crates/lang-rules/src/emit/interface_cpp/enhanced_codec.rs (Commit 45ead22cc2b9), crates/lang-rules/src/emit/interface_java/enhanced.rs, crates/lang-rules/src/emit/interface_java/enhanced_calls.rs (Commit 2ea77f7dad8a); Auswahl über zerodds-idlc generate --rpc-mapping basic|enhanced|enhanced-empty (Commit c17fbe91ffe7); Laufzeit zerodds_rpc::endpoint_options::RpcMapping::Enhanced (Commit e305669e2c42)

Tests: crates/rpc/src/codegen.rs::tests::enhanced_request_is_a_choice_over_the_operations, crates/lang-rules/tests/enhanced_bindings.rs::the_model_is_the_clause, crates/rpc-rust-e2e/tests/enhanced_e2e.rs::an_enhanced_call_is_answered_through_the_related_sample_identity

Status: done — Request-, Reply-, In-, Out- und Result-Strukturen mit @Choice, @Autoid, remoteEx und flacher Vererbung entstehen im Modell und in den Generatoren für Rust, C++ und Java; die Rust-Laufzeit korreliert über PID_RELATED_SAMPLE_IDENTITY.

§7.5.1.2.1 Annotationen im Modul dds::rpc

Spec: §7.5.1.2.1, S. 43 — “All annotations below are defined in the dds::rpc module.”

Repo: crates/ast/src/node/annotation.rs (BUILTIN_ANNOTATIONS: Choice, Autoid, Empty, Mutable; Commit 6c7f585a36ee); crates/idl-lower/src/annotation.rs::Lowering::apply_user_annotation (Commit b53b12d04ba2)

Tests: crates/ast/tests/node_space.rs::every_builtin_annotation_of_the_spec_list_is_present, crates/idl-lower/tests/annotations.rs::the_dds_rpc_annotations_resolve_to_their_builtin_declarations, crates/idl-lower/tests/annotations.rs::the_qualified_dds_rpc_spelling_is_the_same_annotation

Status: done — die Annotationen des Moduls sind vordefiniert und lösen unter ihrem einfachen Namen (@Choice) und in der qualifizierten Schreibung (@dds::rpc::Choice, @dds::rpc::Autoid) auf dieselbe Deklaration auf (Test crates/idl-lower/tests/annotations.rs::the_qualified_dds_rpc_spelling_is_the_same_annotation, Commit ecda940289b7). Das Modell hält die Deklarationen im eingebauten Modul @builtin; ein Modul dds::rpc in crates/ast würde die festen Indizes der eingebauten Knoten verschieben, und die Spec verlangt den Namen, nicht eine Modulstruktur des Modells. Eine eingebaute Annotation hat keine TypeObject und erscheint nicht als ann_custom; der Modulname ist in keiner Ausgabe sichtbar (kein TypeObject und keine erzeugte Datei nennt die Deklaration; nur scoped_name_of liefert intern @builtin::Choice; aus dem Code gelesen, nicht gemessen) (9df3125c22b8, Test crates/lang-rules/tests/enhanced_bindings.rs::a_choice_structure_written_in_idl_has_a_mutable_type_object_with_optional_members).

§7.5.1.2.1.1 @Choice: Deklaration

Spec: §7.5.1.2.1.1, S. 43 — “The @Choice annotation is a placeholder annotation defined as follows. @Annotation local interface Choice { };”

Repo: crates/ast/src/node/annotation.rs (BUILTIN_ANNOTATIONS, Eintrag Choice; Commit 6c7f585a36ee)

Tests: crates/ast/tests/node_space.rs::every_builtin_annotation_of_the_spec_list_is_present

Status: done — Choice ist eine vordefinierte Annotation ohne Member.

§7.5.1.2.1.1 @Choice nur an Strukturen

Spec: §7.5.1.2.1.1, S. 43 — “The @Choice annotation is allowed on structures only.”

Repo: crates/idl-lower/src/annotation.rs::Lowering::misplaced (Eintrag für Choice; Commit ecda940289b7)

Tests: crates/idl-lower/tests/annotations.rs::choice_is_refused_on_anything_but_a_structure

Status: done — @Choice an einer Union, einem Member, einem Interface und einer Aufzählung wird mit einem Fehler abgelehnt; an einer Struktur wird es angenommen.

§7.5.1.2.1.1 @Choice: MUTABLE und alle Member @Optional

Spec: §7.5.1.2.1.1, S. 43 — “When present, the structure shall be interpreted as if the structure had the @Extensibility(MUTABLE_EXTENSIBILITY) annotation and all the members of the structure had the @Optional annotation.”

Repo: crates/rpc/src/codegen.rs::autoid_choice; crates/lang-rules/src/emit/interface_rust/enhanced.rs (choice_codec: DHEADER und ein EMHEADER je vorhandenem Member), crates/lang-rules/src/emit/interface_cpp/enhanced.rs (std::optional-Member), crates/lang-rules/src/emit/interface_cpp/enhanced_codec.rs, crates/lang-rules/src/emit/interface_java/enhanced.rs, crates/lang-rules/src/emit/interface_java/enhanced_calls.rs (Commits 41b3b02f7a20, 45ead22cc2b9, 2ea77f7dad8a)

Tests: crates/rpc-rust-e2e/tests/enhanced_generated.rs::a_request_is_a_mutable_structure_with_one_member, crates/lang-rules/tests/enhanced_cpp_calls.rs::the_codec_writes_the_member_ids_and_length_codes_of_the_clause, crates/lang-rules/tests/enhanced_java_calls.rs::the_codec_writes_the_member_ids_and_length_codes_of_the_clause, crates/idl-lower/tests/annotations.rs::a_choice_structure_is_mutable_with_every_member_optional, crates/idl-lower/tests/annotations.rs::a_choice_structure_cannot_be_final_or_appendable, crates/lang-rules/tests/enhanced_bindings.rs::a_choice_structure_written_in_idl_has_a_mutable_type_object_with_optional_members

Status: done — die vom Generator erzeugten Strukturen (Request, Reply, Result) sind MUTABLE mit optionalen Membern. Eine im IDL geschriebene @Choice-Struktur setzt crates/idl-lower auf MUTABLE und alle Member auf @optional; ihr TypeObject ist MUTABLE mit optionalen Membern. Eine ausdrücklich @final oder @appendable erklärte @Choice-Struktur ist ein Fehler. Commit ecda940289b7.

§7.5.1.2.1.1 @Choice: genau ein Member vorhanden

Spec: §7.5.1.2.1.1, S. 43 — “Furthermore, exactly one member shall be present at any given time.”

Repo: crates/lang-rules/src/emit/interface_rust/enhanced.rs (enum mit einer Variante je Member); crates/lang-rules/src/emit/interface_cpp/enhanced_codec.rs und crates/lang-rules/src/emit/interface_java/enhanced_calls.rs (Zählung der gesetzten Member beim Schreiben, Fehler bei einer Zahl ungleich 1; Commits 41b3b02f7a20, 45ead22cc2b9, 2ea77f7dad8a)

Tests: crates/rpc-rust-e2e/tests/enhanced_generated.rs::a_request_is_a_mutable_structure_with_one_member, crates/rpc-rust-e2e/tests/enhanced_generated.rs::a_request_with_two_active_members_is_refused, crates/rpc-rust-e2e/tests/enhanced_generated.rs::a_choice_without_a_member_is_refused, crates/lang-rules/tests/enhanced_java_calls.rs::a_choice_holds_exactly_one_member_on_both_sides_of_the_codec, crates/rpc/tests/java_enhanced_codec.rs::the_generated_java_service_and_client_answer_the_error_cases_of_the_clauses

Status: done — in Rust ist durch die enum-Form genau ein Member vorhanden; der Decoder lehnt null oder zwei Member ab (Tests; Commit f88947810821). In Java lehnen Encoder und Decoder null und mehr als einen Member ab, die erzeugte Laufzeit antwortet mit RemoteInvalidArgumentError (Tests; Commit 82ec363b6b82). In C++ zählt der Codec die gesetzten Member beim Schreiben und wirft dds::rpc::UnsupportedError bei einer Zahl ungleich 1; der Decoder lehnt null und zwei Member ab (869a329a6b48). Test: crates/rpc/tests/cpp/enhanced_function_call_roundtrip.cpp über crates/rpc/tests/cpp_enhanced_function_call.rs::the_generated_enhanced_client_calls_the_generated_enhanced_service (Oktette ohne Member und mit zwei Membern werden abgewiesen und auf der Leitung mit REMOTE_EX_INVALID_ARGUMENT beantwortet; 49525d7e5e80, auf dem Linux-Testhost gelaufen).

§7.5.1.2.1.2 @Autoid an Strukturen und Membern

Spec: §7.5.1.2.1.2, S. 43 — “The @Autoid annotation shall be allowed on structures and data members.”

Repo: crates/ast/src/node/annotation.rs (BUILTIN_ANNOTATIONS, Eintrag Autoid; Commit 6c7f585a36ee); crates/idl-lower/src/annotation.rs::enumerated_parameter (liest das Argument HASH/SEQUENTIAL)

Tests: crates/ast/tests/node_space.rs::every_builtin_annotation_of_the_spec_list_is_present, crates/idl-lower/tests/annotations.rs::autoid_on_a_structure_assigns_hashed_member_ids, crates/idl-lower/tests/annotations.rs::autoid_on_a_member_hashes_that_members_name, crates/idl-lower/tests/annotations.rs::autoid_is_refused_where_there_are_no_member_ids, crates/lang-rules/tests/enhanced_bindings.rs::an_autoid_structure_written_in_idl_has_hashed_member_ids_in_its_type_object

Status: done — Lowering::misplaced lässt @Autoid an Strukturen und Strukturmembern zu und lehnt es an anderen Elementen ab. An einer im IDL geschriebenen Struktur setzt Lowering::dds_rpc_autoid für jeden Member die Member-ID als HASH des Membernamens (hashed_member_id); an einem einzelnen Member gilt der HASH seines Namens. Das TypeObject trägt diese IDs. Commit ecda940289b7.

§7.5.1.2.1.2 Synthetisierte Strukturen tragen @Autoid

Spec: §7.5.1.2.1.2, S. 43 — “The structures of the topic types synthesized from the interface shall be annotated as @Autoid.”

Repo: crates/rpc/src/codegen.rs::autoid; crates/lang-rules/src/adapter/interface.rs::autoid_struct (Commit 0edbbcf11324)

Tests: crates/lang-rules/tests/enhanced_bindings.rs::the_model_is_the_clause

Status: done — jede synthetisierte Struktur hat autoid: true; der Test vergleicht die Auszeichnung (@Autoid oder @Choice @Autoid) aller Strukturen des Beispiels Calculator mit der Liste aus §7.5.1.2.

§7.5.1.2.1.2 Member-ID ist HASH des Namens

Spec: §7.5.1.2.1.2, S. 43 — “The @Autoid annotation indicates that the member-id of each member shall be computed using the HASH algorithm (defined in 7.5.1.1.2 The Hashing Algorithm) applied to the name of the member.”

Repo: crates/rpc/src/codegen.rs::autoid mit MEMBER_ID_MASK und crate::rpc_hash::rpc_member_hash; crates/lang-rules/src/adapter/interface.rs::member_id (Commit 0edbbcf11324)

Tests: crates/rpc/src/codegen.rs::tests::enhanced_autoid_member_ids_are_the_hash_of_the_name, crates/lang-rules/tests/enhanced_bindings.rs::the_member_ids_are_the_hash_of_the_names, crates/rpc-rust-e2e/tests/enhanced_generated.rs::a_request_is_a_mutable_structure_with_one_member

Status: done — die Member-ID ist der HASH des Namens (§7.5.1.1.2), auf die unteren 28 Bit maskiert (0x0FFF_FFFF), weil ein EMHEADER nach XTypes 1.3 §7.4.3.4.2 eine Member-ID mit 28 Bit trägt. Der HASH selbst hat 32 Bit.

§7.5.1.2.1.2 Kollisionen der Member-IDs als Fehler melden

Spec: §7.5.1.2.1.2, S. 44 — “The collisions of member-ids produced as a result of @Autoid annotation must be detected. If a structure annotated as @Autoid has a hash collision due to two or more member names map to the same hash-code, the collision shall be reported as an error.”

Repo: crates/rpc/src/codegen.rs::autoid (RpcError::MemberIdCollision; Commit 0edbbcf11324); crates/lang-rules/src/adapter/interface.rs::autoid_struct (BindingError::Codec; Commit 0edbbcf11324)

Tests: crates/rpc/src/codegen.rs::tests::enhanced_member_id_collision_is_an_error

Status: done — m9852 und m12254 liefern dieselbe 28-Bit-ID und ergeben MemberIdCollision. Der Pfad des Generators (autoid_struct in interface.rs) prüft ebenso; er hat keinen eigenen Test.

§7.5.1.2.1.3 @Empty erlaubt eine leere Struktur

Spec: §7.5.1.2.1.3, S. 44 — “The @Empty annotation allows a structure to be empty. The code synthesized from an empty structure is implementation dependent.”

Repo: crates/rpc/src/codegen.rs::EmptyOperationStyle::EmptyAnnotation und EnhancedOptions (Commit d1824c24a497); zerodds-idlc generate --rpc-mapping enhanced-empty (Commit c17fbe91ffe7); Codecs für eine Struktur ohne Member in crates/lang-rules/src/emit/interface_rust/enhanced.rs, crates/lang-rules/src/emit/interface_cpp/enhanced_codec.rs, crates/lang-rules/src/emit/interface_java/enhanced_calls.rs

Tests: crates/rpc/src/codegen.rs::tests::enhanced_empty_operation_can_be_an_empty_structure, crates/lang-rules/tests/enhanced_empty_style.rs::the_empty_structure_reading_gives_it_no_member, crates/rpc-rust-e2e/tests/enhanced_empty.rs::an_empty_structure_has_no_octets

Status: done — eine Operation ohne zu tragende Werte kann als leere Struktur mit @Empty abgebildet werden; die Voreinstellung bleibt das Member dummy (§7.5.1.1.4 Regel 3c, Beispiel in §7.5.1.2.6).

§7.5.1.2.1.4 @Mutable an Operationen

Spec: §7.5.1.2.1.4, S. 44 — “This annotation shall be allowed on interface operations.”

Repo: crates/lang-rules/src/adapter/interface.rs (Operation::mutable aus applied_annotation(&op.facets, "Mutable")); crates/rpc/src/service_mapping.rs (MethodDef::mutable); Commits 6c7f585a36ee, b53b12d04ba2

Tests: crates/idl-lower/tests/annotations.rs::the_dds_rpc_annotations_resolve_to_their_builtin_declarations, crates/rpc/src/codegen.rs::tests::enhanced_mutable_operation_has_mutable_structures

Status: done — @Mutable an einer Operation löst auf und wird gelesen.

§7.5.1.2.1.4 @Mutable macht Call- und Return-Strukturen MUTABLE

Spec: §7.5.1.2.1.4, S. 44 — “The use of the @Mutable operation changes the type declaration of the synthesized call and return structures so that they are declared with the @Extensibility(MUTABLE_EXTENSIBILITY) annotation.”

Repo: crates/rpc/src/codegen.rs::build_enhanced_operation (method.mutable für In, Out und Result); crates/lang-rules/src/emit/interface_rust/enhanced.rs::mutable_struct_codec (Commit 41b3b02f7a20)

Tests: crates/rpc/src/codegen.rs::tests::enhanced_mutable_operation_has_mutable_structures, crates/rpc-rust-e2e/tests/enhanced_generated.rs::a_mutable_operation_has_mutable_structures, crates/lang-rules/tests/enhanced_cpp_calls.rs::the_codec_writes_the_member_ids_and_length_codes_of_the_clause

Status: done — die Strukturen der Operation mit @Mutable sind MUTABLE, die der anderen Operationen nicht.

§7.5.1.2.2 In-Struktur wie in der Basic-Abbildung

Spec: §7.5.1.2.2, S. 44 — “The mapping for interface operations is the same as defined in 7.5.1.1.2 The Hashing Algorithm with the following additional rules.”

Repo: crates/rpc/src/codegen.rs::build_enhanced_operation mit method_in_members (Commit 0edbbcf11324)

Tests: crates/rpc/src/codegen.rs::tests::enhanced_inout_param_is_in_both_structures, crates/rpc/src/codegen.rs::tests::enhanced_empty_operation_has_a_dummy_member_by_default

Status: done — die In-Struktur hat die Member der Basic-Abbildung (Parameter in und inout, sonst dummy).

§7.5.1.2.2 @Mutable: In-Struktur MUTABLE

Spec: §7.5.1.2.2, S. 44 — “If the operation has the @Mutable annotation, then the synthesized In structure shall have the annotation @Extensibility(MUTABLE_EXTENSIBILITY).”

Repo: crates/rpc/src/codegen.rs::build_enhanced_operation (autoid_struct(..., method.mutable, ...); Commit 0edbbcf11324)

Tests: crates/rpc/src/codegen.rs::tests::enhanced_mutable_operation_has_mutable_structures, crates/rpc-rust-e2e/tests/enhanced_generated.rs::a_mutable_operation_has_mutable_structures

Status: done

§7.5.1.2.3 Out-Struktur wie in der Basic-Abbildung, @Mutable

Spec: §7.5.1.2.3, S. 44 — “The rules for mapping the Out structure are identical to that defined in 7.5.1.1.5 […] 1. If the operation has the @Mutable annotation, then the synthesized Out structure shall have the annotation @Extensibility(MUTABLE_EXTENSIBILITY).”

Repo: crates/rpc/src/codegen.rs::build_enhanced_operation mit method_out_members (Commit 0edbbcf11324)

Tests: crates/rpc/src/codegen.rs::tests::enhanced_out_carries_the_return_value, crates/rpc/src/codegen.rs::tests::enhanced_mutable_operation_has_mutable_structures

Status: done

§7.5.1.2.3 Result-Struktur ${interfaceName}_${operationName}_Result

Spec: §7.5.1.2.3, S. 44 — “Each operation in the interface shall map to an Out structure and a Result structure. […] 2. The Result structure name shall be “${interfaceName}_${operationName}_Result.””

Repo: crates/rpc/src/codegen.rs::build_enhanced_operation (Commit 0edbbcf11324)

Tests: crates/rpc/src/codegen.rs::tests::enhanced_result_carries_out_and_the_exceptions

Status: done

§7.5.1.2.3 Result-Struktur mit @Choice

Spec: §7.5.1.2.3, S. 44 — “3. The Result structure shall have the annotation @Choice.”

Repo: crates/rpc/src/codegen.rs::build_enhanced_operation (autoid_choice; Commit 0edbbcf11324)

Tests: crates/rpc/src/codegen.rs::tests::enhanced_result_carries_out_and_the_exceptions, crates/lang-rules/tests/enhanced_bindings.rs::the_model_is_the_clause

Status: done

§7.5.1.2.3 Result-Struktur mit @Autoid

Spec: §7.5.1.2.3, S. 44 — “4. The Result structure shall have the annotation @Autoid.”

Repo: crates/rpc/src/codegen.rs::build_enhanced_operation (autoid_choice; Commit 0edbbcf11324)

Tests: crates/rpc/src/codegen.rs::tests::enhanced_result_carries_out_and_the_exceptions, crates/lang-rules/tests/enhanced_bindings.rs::the_model_is_the_clause

Status: done

§7.5.1.2.3 Result-Struktur: erster Member result

Spec: §7.5.1.2.3, S. 44 — “5. The Result structure shall have a first member with name “result” and with type ${interfaceName}_${operationName}_Out.”

Repo: crates/rpc/src/codegen.rs::build_enhanced_operation (RESULT_MEMBER; Commit 0edbbcf11324)

Tests: crates/rpc/src/codegen.rs::tests::enhanced_result_carries_out_and_the_exceptions

Status: done ### §7.5.1.2.3 Result-Struktur: ein Member je Exception

Spec: §7.5.1.2.3, S. 44 — “6. The Result structure name shall have members for each exception an operation may raise. a. The member name shall be synthetized as the lower-case version of the exception name with the suffix “_ex” added. b. The type associated with the member shall be the exception type.”

Repo: crates/rpc/src/codegen.rs::build_enhanced_operation (Member <exception>_ex, Name in Kleinbuchstaben), crates/lang-rules/src/adapter/interface.rs::enhanced_service

Tests: crates/rpc/src/codegen.rs::tests::enhanced_result_carries_out_and_the_exceptions, crates/lang-rules/tests/enhanced_bindings.rs::the_model_is_the_clause, crates/rpc-rust-e2e/tests/enhanced_generated.rs::a_result_is_a_choice_of_the_result_and_the_exceptions

Status: done — das Modell legt je Exception ein Member <kleingeschriebener Name>_ex vom Typ der Exception an (0edbbcf11324; 41b3b02f7a20 für die Generatoren). Das Rust-Binding kodiert das Member mit der Member-ID toobig_ex.

§7.5.1.2.3 @Mutable: Result-Struktur MUTABLE

Spec: §7.5.1.2.3, S. 44 — “7. If the operation has the @Mutable annotation, then the synthesized Result structure shall have the annotation @Extensibility(MUTABLE_EXTENSIBILITY).”

Repo: crates/rpc/src/codegen.rs::build_enhanced_operation (MethodDef::mutable setzt EnhancedStruct::mutable an In, Out und Result), crates/lang-rules/src/adapter/interface.rs::enhanced_service

Tests: crates/rpc/src/codegen.rs::tests::enhanced_mutable_operation_has_mutable_structures, crates/rpc-rust-e2e/tests/enhanced_generated.rs::a_mutable_operation_has_mutable_structures

Status: done — Hat die Operation @Mutable, sind In, Out und Result MUTABLE, bei anderen Operationen nicht (0edbbcf11324; 41b3b02f7a20). Der zweite Test prüft die Oktette der In-Struktur (DHEADER und EMHEADER je Member); für Result prüft ihn nur das Modell.

§7.5.1.2.4 Request-Struktur ${interfaceName}_Request

Spec: §7.5.1.2.4, S. 45 — “Each interface shall map to a Request structure. […] 1. The Request structure name shall be “${interfaceName}_Request.””

Repo: crates/rpc/src/codegen.rs::build_enhanced_service_with (${interfaceName}_Request), crates/lang-rules/src/adapter/interface.rs::enhanced_service

Tests: crates/rpc/src/codegen.rs::tests::enhanced_request_is_a_choice_over_the_operations, crates/lang-rules/tests/enhanced_bindings.rs::the_model_is_the_clause

Status: done — jedes Interface erhält genau eine Struktur ${interfaceName}_Request (0edbbcf11324; 41b3b02f7a20). Die Generatoren für Rust, C++ und Java deklarieren sie (enhanced_bindings.rs::rust_declares_the_structures_of_the_clause, cpp_declares_the_structures_of_the_clause, java_declares_the_structures_of_the_clause).

§7.5.1.2.4 Request-Struktur mit @Choice

Spec: §7.5.1.2.4, S. 45 — “2. The Request structure shall have the @Choice annotation.”

Repo: crates/rpc/src/codegen.rs::autoid_choice, crates/lang-rules/src/adapter/interface.rs::enhanced_service

Tests: crates/rpc/src/codegen.rs::tests::enhanced_request_is_a_choice_over_the_operations, crates/lang-rules/tests/enhanced_bindings.rs::the_model_is_the_clause, crates/rpc-rust-e2e/tests/enhanced_generated.rs::a_request_is_a_mutable_structure_with_one_member

Status: done — EnhancedStruct::choice ist für die Request-Struktur gesetzt (0edbbcf11324; 41b3b02f7a20). Das Rust-Binding kodiert sie als PL_CDR2-Objekt mit genau einem Member (DHEADER, EMHEADER, Member).

§7.5.1.2.4 Request-Struktur mit @Autoid

Spec: §7.5.1.2.4, S. 45 — “3. The Request structure shall have the @Autoid annotation.”

Repo: crates/rpc/src/codegen.rs::autoid (Member-ID = HASH des Namens, 28 Bit), crates/lang-rules/src/adapter/interface.rs::enhanced_service

Tests: crates/rpc/src/codegen.rs::tests::enhanced_autoid_member_ids_are_the_hash_of_the_name, crates/rpc/src/codegen.rs::tests::enhanced_member_id_collision_is_an_error, crates/lang-rules/tests/enhanced_bindings.rs::the_member_ids_are_the_hash_of_the_names

Status: done — die Request-Struktur trägt @Autoid; die Member-ID ist der auf 28 Bit gekürzte HASH des Member-Namens (0edbbcf11324; 41b3b02f7a20). Eine Kollision zweier Namen ist ein Fehler (RpcError::MemberIdCollision).

§7.5.1.2.4 Request-Struktur: ein Member je Operation

Spec: §7.5.1.2.4, S. 45 — “4. The Request structure shall contain a member for each operation in the interface. a. The member name shall be the operation name. b. The member type shall be ${interfaceName}_${operationName}_In.”

Repo: crates/rpc/src/codegen.rs::build_enhanced_service_with (Member je Operation, Typ ${I}_${op}_In), crates/lang-rules/src/adapter/interface.rs::enhanced_service

Tests: crates/rpc/src/codegen.rs::tests::enhanced_request_is_a_choice_over_the_operations, crates/rpc/src/codegen.rs::tests::enhanced_inheritance_is_flattened, crates/lang-rules/tests/enhanced_bindings.rs::the_model_is_the_clause

Status: done — Member-Name ist der Operationsname, Typ ${interfaceName}_${operationName}_In; geerbte Operationen tragen den Typnamen ihres Basis-Interface (Adder_add_In). 0edbbcf11324; 41b3b02f7a20.

§7.5.1.2.5 Reply-Struktur ${interfaceName}_Reply

Spec: §7.5.1.2.5, S. 46 — “Each interface shall map to a Reply structure. […] 1. The Reply structure name shall be “${interfaceName}_Reply”.”

Repo: crates/rpc/src/codegen.rs::build_enhanced_service_with (${interfaceName}_Reply), crates/lang-rules/src/adapter/interface.rs::enhanced_service

Tests: crates/rpc/src/codegen.rs::tests::enhanced_reply_has_the_results_and_remote_ex, crates/lang-rules/tests/enhanced_bindings.rs::the_model_is_the_clause

Status: done — jedes Interface erhält genau eine Struktur ${interfaceName}_Reply (0edbbcf11324; 41b3b02f7a20). Die drei Generatoren deklarieren sie (enhanced_bindings.rs::rust_declares_the_structures_of_the_clause, cpp_declares_the_structures_of_the_clause, java_declares_the_structures_of_the_clause).

§7.5.1.2.5 Reply-Struktur mit @Choice

Spec: §7.5.1.2.5, S. 46 — “2. The Reply structure shall have the @Choice annotation.”

Repo: crates/rpc/src/codegen.rs::autoid_choice, crates/lang-rules/src/adapter/interface.rs::enhanced_service

Tests: crates/rpc/src/codegen.rs::tests::enhanced_reply_has_the_results_and_remote_ex, crates/lang-rules/tests/enhanced_bindings.rs::the_model_is_the_clause, crates/rpc-rust-e2e/tests/enhanced_generated.rs::a_reply_carries_remote_ex

Status: done — EnhancedStruct::choice ist für die Reply-Struktur gesetzt (0edbbcf11324; 41b3b02f7a20). Das Rust-Binding kodiert einen Reply mit remoteEx als Objekt mit einem Member.

§7.5.1.2.5 Reply-Struktur mit @Autoid

Spec: §7.5.1.2.5, S. 46 — “3. The Reply structure shall have the @Autoid annotation.”

Repo: crates/rpc/src/codegen.rs::autoid, crates/lang-rules/src/adapter/interface.rs::enhanced_service

Tests: crates/rpc/src/codegen.rs::tests::enhanced_autoid_member_ids_are_the_hash_of_the_name, crates/lang-rules/tests/enhanced_bindings.rs::the_member_ids_are_the_hash_of_the_names

Status: done — die Reply-Struktur trägt @Autoid, Member-ID wie bei der Request-Struktur (0edbbcf11324; 41b3b02f7a20). the_member_ids_are_the_hash_of_the_names prüft alle Strukturen des Modells, die Reply-Struktur eingeschlossen.

§7.5.1.2.5 Reply-Struktur: ein Member je Operation

Spec: §7.5.1.2.5, S. 46 — “4. The Reply structure shall contain a member for each operation in the interface. a. The member name shall be the operation name. b. The member type shall be ${interfaceName}_${operationName}_Result.”

Repo: crates/rpc/src/codegen.rs::build_enhanced_service_with (Member je Operation, Typ ${I}_${op}_Result), crates/lang-rules/src/adapter/interface.rs::enhanced_service

Tests: crates/rpc/src/codegen.rs::tests::enhanced_reply_has_the_results_and_remote_ex, crates/rpc/src/codegen.rs::tests::enhanced_inheritance_is_flattened, crates/lang-rules/tests/enhanced_bindings.rs::the_model_is_the_clause

Status: done — Member-Name ist der Operationsname, Typ ${interfaceName}_${operationName}_Result; geerbte Operationen tragen den Typnamen der Basis (Subtractor_sub_Result). 0edbbcf11324; 41b3b02f7a20.

§7.5.1.2.5 Reply-Struktur: Member remoteEx

Spec: §7.5.1.2.5, S. 46 — “5. The Reply structure shall contain a member named “remoteEx” of type dds::rpc::RemoteException_t. If an interface has an operation named remoteEx (case-sensitive), the corresponding Reply structure shall contain a member named remoteEx_N and type RemoteException_t, where N is the first integer in the range 1 to 2^31 that avoids the collision.”

Repo: crates/rpc/src/codegen.rs::remote_ex_member_name, crates/lang-rules/src/adapter/interface.rs::remote_ex_member_name, crates/rpc/src/enhanced.rs::encode_remote_ex_reply

Tests: crates/rpc/src/codegen.rs::tests::enhanced_reply_has_the_results_and_remote_ex, crates/rpc/src/codegen.rs::tests::enhanced_remote_ex_avoids_an_operation_of_that_name, crates/rpc/src/enhanced.rs::tests::a_remote_ex_member_renamed_for_a_colliding_operation_is_found_by_its_name, crates/rpc-rust-e2e/tests/enhanced_e2e.rs::an_enhanced_remote_exception_is_the_remote_ex_member

Status: done — die Reply-Struktur hat das Member remoteEx; heißt eine Operation so, lautet es remoteEx_N mit dem ersten freien N ab 1 (0edbbcf11324; 41b3b02f7a20). Als Typ steht RemoteExceptionCode_t: den von der Spec genannten Typ dds::rpc::RemoteException_t definiert die Spec nicht, §7.5.1.1.1 und §7.5.2 definieren RemoteExceptionCode_t (Widerspruch innerhalb der Spec). Die Tests prüfen N = 1; ein Fall mit einer Operation remoteEx_1 (N = 2) hat keinen Test.

§7.5.1.2.2 bis §7.5.1.2.5 Beispiele

Spec: §7.5.1.2.3–§7.5.1.2.5, S. 45–46 — Beispiele für RobotControl (“Non-normative example”).

Repo: —

Tests: —

Status: n/a (informative) — Beispiele. Die Struktur des Beispiels ist durch die Items zu §7.5.1.2.3 bis §7.5.1.2.5 abgedeckt.

§7.5.1.2.6 Vererbung wird flach gemacht

Spec: §7.5.1.2.6, S. 46 — “A derived interface is interpreted as if all the inherited operations are declared in-place in the derived interface. That is, the inheritance structure is flattened.”

Repo: crates/rpc/src/codegen.rs::build_enhanced_service_with (geerbte Operationen zuerst, Basis für Basis, dann die eigenen), crates/lang-rules/src/adapter/interface.rs::enhanced_service (über operations_with_interface_flattened), crates/lang-rules/src/emit/interface_rust/enhanced.rs (abgeleiteter Dispatcher)

Tests: crates/rpc/src/codegen.rs::tests::enhanced_inheritance_is_flattened, crates/lang-rules/tests/enhanced_bindings.rs::the_model_is_the_clause, crates/rpc-rust-e2e/tests/enhanced_generated.rs::a_derived_request_has_the_inherited_operation, crates/rpc-rust-e2e/tests/enhanced_generated.rs::a_derived_dispatcher_serves_an_inherited_member

Status: done — Request und Reply des abgeleiteten Interface enthalten die geerbten Operationen unter den Typnamen der Basis; der abgeleitete Dispatcher beantwortet sie (0edbbcf11324, 41b3b02f7a20, 7607e8680852).

§7.5.1.2.6 Beispiel Calculator

Spec: §7.5.1.2.6, S. 46–49 — Enhanced-Abbildung von Calculator : Adder, Subtractor (“Non-normative Example”).

Repo: —

Tests: crates/lang-rules/tests/enhanced_bindings.rs::the_model_is_the_clause (nimmt das Beispiel als Vorlage)

Status: n/a (informative) — Beispiel. Die Strukturen des Beispiels stehen als Erwartung in the_model_is_the_clause.

§7.5.1.2.6 Kompatibilität über die Regeln der Zuweisbarkeit

Spec: §7.5.1.2.6, S. 49 — “The Enhanced Service Mapping leverages the assignability rules defined in the [DDS-XTypes] specification to ensure that the topic types remain compatible in case of inheritance. A client using the base interface can invoke an operation in a service that implements a derived interface as long as the same topic names are used.”

Repo: crates/rpc/src/codegen.rs::build_enhanced_service_with (gleiche Member-IDs und Typnamen der Basis, topic_aliases je Elternteil über ServiceDef::topic_names), crates/discovery/src/sedp/cache.rs::topics_correspond (Zuordnung über topic_aliases)

Tests: crates/rpc/src/codegen.rs::tests::enhanced_inheritance_is_flattened, crates/rpc/src/topic_naming.rs::tests::every_parent_interface_contributes_one_alias, crates/dcps/tests/topic_alias_matching.rs::a_reader_on_an_alias_matches_the_writer_over_the_wire, crates/rpc-rust-e2e/tests/enhanced_generated.rs::a_member_the_interface_does_not_have_is_unknown_operation, crates/rpc-rust-e2e/tests/java_peer.rs::a_java_client_calls_a_rust_service, crates/rpc-rust-e2e/tests/java_peer.rs::a_rust_client_calls_a_java_service, crates/rpc-rust-e2e/tests/java_peer.rs::a_java_client_of_the_base_calls_a_rust_service_of_the_derived_interface, crates/rpc-rust-e2e/tests/java_peer.rs::a_rust_client_of_the_base_calls_a_java_service_of_the_derived_interface, crates/java-omgdds/java/src/test/java/org/zerodds/rtps/TypeConsistencyTest.java

Status: done — Rust und C++ sind umgesetzt und gemessen: gleiche Member-IDs für geerbte Operationen, Topic-Aliase der Eltern, Zuordnung über Aliase (bdf9ab1e6caa), Überspringen unbekannter Member, und die Topics tragen die TypeInformation ihrer Typen, so dass decide_type_consistency die Zuweisbarkeit auswertet (Rust a2bc3b857739; C++ über zerodds_writer_create_qos_typed und zerodds_reader_create_qos_typed der C-API, 1f0f710986f4, bb1220c3d1b2). Tests: crates/rpc-rust-e2e/tests/enhanced_type_information.rs::base_and_derived::a_base_client_calls_a_derived_service (Rust), crates/rpc/tests/cpp_rpc_real_library.rs::the_cpp_binding_runs_against_libzerodds (C++, Alt-Client gegen Neu-Service über ev_old/ev_new), Struktur der Objekte: crates/lang-rules/tests/enhanced_type_information.rs (Linux-Testhost, grün). Die Java-Laufzeit kündigt die TypeInformation an (TypeDescription, RawTypeSupport, vom Generator geschrieben: 145d0036dd82, 87d07b3ff2a3); der erzeugte Java-Code ist übersetzt und gelaufen (crates/rpc/tests/java_rpc_runtime.rs), und ein Java-Peer gegen einen Rust-Peer ist gemessen (dbb935492284, Tests java_peer.rs, Linux-Testhost). Java paart wie Rust nach der Zuweisbarkeit (2d0f809c6e2, 9b1608508c5, d67a980f80b; Item „§7.5.1.2.6 Java: Paarung der Endpunkte nach Aliasen und Zuweisbarkeit“): crates/rpc-rust-e2e/tests/java_peer.rs misst gegen Rust-Peers den Client der Basis gegen den Dienst des abgeleiteten Interface in beiden Richtungen, einen geänderten Parametertyp und einen auf long long erweiterten Rückgabetyp (beide ohne Match auf der Java-Seite) und ein an eine @mutable-Struktur angehängtes Member (Match, die Antwort wird gelesen); Einheitstest TypeConsistencyTest.java (9 Fälle).

§7.5.2 Lokale und entfernte Fehlercodes

Spec: §7.5.2, S. 49–50 — “Error codes are (conceptually) classified as local and remote. The error codes described in the [DDS] PIM are all local error codes. This specification further adds remote error codes […] represented using the RemoteExceptionCode_t IDL enumeration below.”

Repo: —

Tests: —

Status: n/a (informative) — Einordnung; die Aufzählung ist bei §7.5.1.1.1 geführt.

§7.5.2 REMOTE_EX_OK

Spec: §7.5.2, S. 50 — “REMOTE_EX_OK — The request was executed successfully.”

Repo: crates/rpc/src/replier.rs::Replier::tick (RemoteExceptionCode::Ok nach erfolgreichem Handler), Replier::send_reply

Tests: crates/rpc/src/replier.rs::tests::tick_processes_request_and_writes_reply, crates/rpc/src/replier.rs::tests::receive_requests_and_send_reply_expose_the_identity

Status: done — der Replier schreibt den Code Ok mit dem Reply; Commit der Tests f06c1eaf3d3a (Replier), c5af5c7c138e (send_reply).

§7.5.2 REMOTE_EX_UNSUPPORTED

Spec: §7.5.2, S. 50 — “REMOTE_EX_UNSUPPORTED — Operation is valid but it is unsupported (a.k.a. not implemented).”

Repo: crates/lang-rules/src/emit/interface_rust.rs::dispatcher_handle_fn (unbekannte Operation, §7.7.1.1), crates/lang-rules/src/emit/interface_java/calls.rs (Dispatcher des Java-Service), crates/rpc/src/replier.rs::Replier::send_exception

Tests: crates/rpc-rust-e2e/tests/e2e.rs::the_generated_calculator_binding_runs_every_call, crates/rpc/tests/java_rpc_runtime.rs::the_generated_function_call_client_calls_the_generated_service (FunctionCallRoundtrip.java), crates/rpc/tests/cpp_function_call.rs::the_generated_client_calls_the_generated_service (function_call_roundtrip.cpp), crates/rpc/src/replier.rs::tests::send_exception_answers_with_the_code

Status: done — der erzeugte Rust-Dispatcher, der erzeugte Java-Service und der erzeugte C++-Service antworten in der Basic-Abbildung auf eine Operation, die der Service nicht kennt, mit REMOTE_EX_UNSUPPORTED (§7.7.1.1; Rust b527a9f58028, Java c512ee365514, C++ 62ccb5f757a3). Der Default-Zweig von answer_method in crates/lang-rules/src/emit/interface_cpp/calls.rs wirft RemoteUnsupportedError; function_call_roundtrip.cpp erwartet diesen Fehler beim Client.

§7.5.2 REMOTE_EX_INVALID_ARGUMENT

Spec: §7.5.2, S. 50 — “REMOTE_EX_INVALID_ARGUMENT — The value of the parameter passed has an illegal value (e.g., two options active in a @Choice structure).”

Repo: crates/rpc/src/replier.rs::Replier::tick (Nutzlast nicht dekodierbar, und Code des Handlers), runtime/cpp/include/dds/rpc/core.hpp::detail::remote_exception_code_of (RemoteInvalidArgumentError)

Tests: crates/rpc/src/replier.rs::tests::tick_propagates_handler_error_into_reply, crates/rpc/src/replier.rs::tests::tick_answers_an_undecodable_payload_with_invalid_argument, crates/rpc/src/replier.rs::tests::receive_requests_answers_an_undecodable_payload_with_invalid_argument, crates/rpc/tests/runtime_e2e.rs::e2e_handler_error_surfaces_as_remote_exception_at_caller, crates/rpc-rust-e2e/tests/enhanced_generated.rs::a_request_with_two_active_members_is_refused, crates/rpc-rust-e2e/tests/enhanced_generated.rs::a_choice_without_a_member_is_refused, crates/rpc-rust-e2e/tests/enhanced_generated.rs::the_generated_service_answers_two_active_members_with_invalid_argument, crates/rpc/tests/java_enhanced_codec.rs::the_generated_java_service_and_client_answer_the_error_cases_of_the_clauses (EnhancedRuntimeChecks.java), crates/lang-rules/tests/enhanced_java_calls.rs::a_choice_holds_exactly_one_member_on_both_sides_of_the_codec, crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together (rpc_runtime_roundtrip.cpp)

Status: done — der Code wird gesendet, wenn der Handler ihn liefert, wenn die Nutzlast eines Requests nicht dekodierbar ist und wenn eine @Choice-Struktur zwei aktive Optionen oder keine trägt. Rust: Replier::tick und Replier::receive_requests (Commits f88947810821, 58b9ca260b4c). Java: der erzeugte Decoder lehnt ab, die Laufzeit antwortet (82ec363b6b82). C++: Replier::pull in runtime/cpp/include/dds/rpc.hpp beantwortet einen Request, den es nicht dekodieren kann, mit REMOTE_EX_INVALID_ARGUMENT, in der Enhanced-Abbildung über die Identität des Samples, in der Basic-Abbildung über die Identität im Header (vorher wurde er verworfen; 49525d7e5e80). Test: crates/rpc/tests/cpp_enhanced_function_call.rs::the_generated_enhanced_client_calls_the_generated_enhanced_service (Antwort auf der Leitung, auf dem Linux-Testhost gelaufen). Der Weg über den Handler ist in C++ getestet (RemoteInvalidArgumentError). Commits der früheren Teile: f06c1eaf3d3a (Weg über den Handler), e305669e2c42 (Fehler-Reply mit Default-Fall der Return-Union).

§7.5.2 REMOTE_EX_OUT_OF_RESOURCES

Spec: §7.5.2, S. 50 — “REMOTE_EX_OUT_OF_RESOURCES — The remote service ran out of resources while processing the request.”

Repo: crates/rpc/src/replier.rs::Replier::send_exception, runtime/cpp/include/dds/rpc/core.hpp::detail::remote_exception_code_of (RemoteOutOfResourcesError)

Tests: crates/rpc/src/replier.rs::tests::tick_answers_out_of_resources, crates/rpc/tests/runtime_e2e.rs::e2e_out_of_resources_surfaces_as_remote_exception_at_caller, crates/rpc/src/replier.rs::tests::send_exception_answers_with_the_code, crates/rpc/tests/java_rpc_runtime.rs::the_java_rpc_runtime_and_the_generated_services_run_together (RpcRuntimeRoundtrip.java, RemoteOutOfResourcesError)

Status: done — eine Anwendung sendet den Code über den Handler (Err(RemoteExceptionCode::OutOfResources)), in C++ und Java über RemoteOutOfResourcesError. Rust: der Replier schreibt den Code, der Aufrufer erhält RemoteException(OutOfResources) (58b9ca260b4c). Java: der Test wirft den Fehler im Service und prüft ihn beim Client. In C++ prüft rpc_runtime_roundtrip.cpp nur die Klassenbeziehung der Fehlerklasse (static_assert). Keine Laufzeit erkennt Ressourcenmangel selbst; die Spec legt nicht fest, wann ein Service Ressourcenmangel meldet. Die Rust-Laufzeit sendet den Code nicht für einen Fehler beim Kodieren des Replies; dieser Fall meldet REMOTE_EX_UNKNOWN_EXCEPTION (b527a9f58028).

§7.5.2 REMOTE_EX_UNKNOWN_OPERATION

Spec: §7.5.2, S. 50 — “REMOTE_EX_UNKNOWN_OPERATION — The operation called is unknown.”

Repo: crates/lang-rules/src/emit/interface_rust/enhanced.rs::answer_unknown_operations (Enhanced, §7.7.2), crates/lang-rules/src/emit/interface_java/enhanced_calls.rs, crates/lang-rules/src/emit/interface_cpp/calls.rs::answer_member

Tests: crates/rpc-rust-e2e/tests/enhanced_generated.rs::an_unknown_member_is_answered_unknown_operation, crates/rpc-rust-e2e/tests/enhanced_generated.rs::a_member_the_interface_does_not_have_is_unknown_operation, crates/rpc-rust-e2e/tests/enhanced_e2e.rs::an_enhanced_remote_exception_is_the_remote_ex_member, crates/rpc/tests/cpp_enhanced_function_call.rs::the_generated_enhanced_client_calls_the_generated_enhanced_service (enhanced_function_call_roundtrip.cpp), crates/rpc/tests/java_enhanced_codec.rs::the_generated_java_service_and_client_answer_the_error_cases_of_the_clauses (EnhancedRuntimeChecks.java)

Status: done — in der Enhanced-Abbildung beantworten die erzeugten Dispatcher eine unbekannte Operation mit REMOTE_EX_UNKNOWN_OPERATION (§7.7.2.1; Rust 41b3b02f7a20). Das Verhalten ist für Rust, C++ (enhanced_function_call_roundtrip.cpp) und Java (EnhancedRuntimeChecks.java, 82ec363b6b82) mit einer laufenden Gegenstelle getestet. Die Basic-Abbildung sendet in diesem Fall REMOTE_EX_UNSUPPORTED (§7.7.1.1, Item oben).

§7.5.2 REMOTE_EX_UNKNOWN_EXCEPTION

Spec: §7.5.2, S. 50 — “REMOTE_EX_UNKNOWN_EXCEPTION — A generic, unspecified exception was raised by the service implementation.”

Repo: crates/lang-rules/src/emit/interface_rust.rs::dispatcher_call_arm_via (Wildcard-Zweig), crates/rpc/src/replier.rs::Replier::tick (Fehler beim Kodieren des Replies), runtime/cpp/include/dds/rpc/core.hpp::detail::remote_exception_code_of, crates/lang-rules/src/emit/interface_java/calls.rs

Tests: crates/rpc/tests/cpp_function_call.rs::the_generated_client_calls_the_generated_service (function_call_roundtrip.cpp), crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together (rpc_runtime_roundtrip.cpp), crates/rpc/tests/java_rpc_runtime.rs::the_generated_function_call_client_calls_the_generated_service (FunctionCallRoundtrip.java), crates/rpc-rust-e2e/tests/e2e.rs::an_exception_the_operation_does_not_declare_is_unknown_exception, crates/rpc-rust-e2e/tests/enhanced_generated.rs::an_exception_the_operation_does_not_declare_is_unknown_exception, crates/rpc-rust-e2e/tests/enhanced_generated.rs::the_generated_client_reports_unknown_exception_for_an_unknown_result_member

Status: done — eine Ausnahme der Implementierung, die weder die Operation deklariert noch ein Remote-Code ist, wird in C++ und Java als REMOTE_EX_UNKNOWN_EXCEPTION gesendet und beim Client als RemoteUnknownExceptionError ausgelöst (C++ ec3707125a9b, Java c512ee365514). Der erzeugte Rust-Dispatcher sendet den Code für eine nicht deklarierte Exception (Tests oben, f88947810821); ein unbekanntes Member des Results meldet der Rust-Client als UnknownException. Für Replier::tick bei einem Reply, der sich nicht kodieren lässt (b527a9f58028), gibt es keinen Test.

§7.5.2 — Verwendung der Codes

Spec: §7.5.2, S. 50 — Tabelle der Bedeutungen.

Repo: crates/rpc/src/replier.rs::Replier::send_error_reply, crates/rpc/src/wire_codec.rs::ERROR_REPLY_DATA

Tests: crates/rpc/src/replier.rs::tests::tick_propagates_handler_error_into_reply, crates/rpc/src/replier.rs::tests::send_exception_answers_with_the_code

Status: done — die Zuordnung der Codes zu den Fällen steht in den Items zu den einzelnen Codes; alle sechs entsprechen der Spec in Rust, C++ und Java (REMOTE_EX_INVALID_ARGUMENT in C++: 49525d7e5e80). Ein Reply mit Fehlercode enthält den Header und den Default-Fall der Return-Union (§7.5.1.1.7 Regel 3); beide Tests prüfen payload == ERROR_REPLY_DATA (e305669e2c42).

§7.5.2 Abbildung auf Exceptions in C++ und Java

Spec: §7.5.2, S. 50 — “Both local and remote exception codes map to exceptions in the C++ and Java language bindings defined in 7.11 Language Bindings.”

Repo: —

Tests: —

Status: n/a (informative) — Verweis; die Abbildung steht in §7.11.1.3 und §7.11.2.1.


§7.6 Discovering and Matching RPC Services

§7.6.1 Basic: eingebaute Discovery ohne Erweiterung

Spec: §7.6.1, S. 50 — “The Basic Service Mapping relies on the built-in discovery provided by the underlying [DDS] compliant implementation. It does not use any extensions to the DDS discovery built-in topics.”

Repo: crates/rpc/src/requester.rs::Requester::from_topics, crates/rpc/src/replier.rs::Replier::from_topics (gewöhnliche DataWriter und DataReader der DCPS-Schicht; set_rpc_discovery wird nur bei RpcMapping::Enhanced aufgerufen)

Tests: crates/rpc-rust-e2e/tests/e2e.rs::the_generated_calculator_binding_runs_every_call, crates/rpc/src/requester.rs::tests::the_basic_mapping_sends_without_a_service_match

Status: done — die Basic-Abbildung benutzt die eingebaute Discovery von DCPS; kein Parameter der Erweiterung wird angekündigt (e305669e2c42).

§7.6.1 Endpunkte von Client und Service über die eingebauten Topics

Spec: §7.6.1, S. 50 — “A client comprises one (or more) DataWriter to send requests and one (or more) DataReader to receive replies. Similarly, a service implementation comprises one (or more) DataReader to receive requests and one (or more) DataWriter to send replies. The built-in publication and subscription topics are used to discover the DataWriter and DataReader at both sides.”

Repo: crates/rpc/src/requester.rs::Requester::from_topics, crates/rpc/src/replier.rs::Replier::from_topics

Tests: crates/rpc-rust-e2e/tests/e2e.rs::the_generated_calculator_binding_runs_every_call

Status: done — der Requester erzeugt einen DataWriter für Requests und einen DataReader für Replies, der Replier einen DataReader und einen DataWriter; die Zuordnung läuft über die eingebauten Publication- und Subscription-Topics (f06c1eaf3d3a).

§7.6.1 Hinweis auf die Wettlaufsituation

Spec: §7.6.1, S. 50 — “Non-normative Note: Service discovery for the Basic Service Mapping is not robust because discovery race conditions can cause the service replies to be lost.”

Repo: —

Tests: crates/rpc/src/requester.rs::tests::the_basic_mapping_sends_without_a_service_match

Status: n/a (informative) — Hinweis. Unter der Basic-Abbildung schreibt der Rust-Requester einen Request sofort, ohne auf das Matching des Reply-Readers zu warten (Requester::service_matched ist dort immer wahr).

§7.6.2 Enhanced: Erweiterung der eingebauten Topics

Spec: §7.6.2, S. 51 — “The Enhanced Service Mapping relies on the built-in discovery service provided by DDS. However, it extends the built-in publication and subscription topic data to avoid the discovery race conditions.” Dazu die Design Rationale.

Repo: —

Tests: —

Status: n/a (informative) — Einleitung; die Erweiterung und die Regeln stehen in den Items unten.

§7.6.2 Client: Request erst nach Discovery des Service-DataWriter

Spec: §7.6.2, S. 51 — “A client must ensure that the client-side DataReader has discovered the service-side DataWriter before writing a request to the service-side DataReader.”

Repo: crates/rpc/src/requester.rs::Requester::wait_for_service, Requester::service_matched, crates/rpc/src/discovery_ext.rs::service_matching_complete (Figure 7.4), runtime/cpp/include/dds/rpc/base.hpp::service_matching_complete, runtime/java/src/main/java/org/zerodds/ddsrpc/RequesterImpl.java

Tests: crates/rpc/src/requester.rs::tests::an_enhanced_request_waits_for_the_service_and_fails_without_sending, crates/rpc/src/requester.rs::tests::the_fail_setting_does_not_wait, crates/rpc/src/discovery_ext.rs::tests::the_client_waits_for_both_service_endpoints, crates/rpc-rust-e2e/tests/enhanced_e2e.rs::the_client_waits_for_the_service_instance_it_names, crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together, crates/zerodds-c-api/tests/rpc_discovery.rs::the_extension_is_announced_read_and_decides_the_matching, crates/rpc/tests/java_rpc_runtime.rs::the_java_rpc_runtime_and_the_generated_services_run_together

Status: done — Rust (e305669e2c42) und C++ (4b6b049312ff, 17a3aef74360) senden einen Enhanced-Request erst, wenn Request-Writer und Reply-Reader einen Service gemeinsam gefunden haben (Figure 7.4: die Endpunkte nennen einander über den related key, und der Request-Reader des Service kündigt den Instanznamen an, den der Client nennt); ServiceMatching::Queue ist die Vorgabe, Fail und Off sind benannte Alternativen. crates/java-omgdds schreibt und liest die PIDs 0x0080 bis 0x0082 (rtps/RpcDiscovery.java, DiscoveryData.buildEndpoint und parseEndpoint, Grenze string<256>: eine Ankündigung darüber wird abgewiesen wie im Decoder von crates/rtps; f65fb3965b5e). ZeroDdsParticipant kündigt service_instance_name an den Endpunkten des Dienstes und related_*_key an beiden Seiten an (9993349aff89). Tests: crates/java-omgdds/java/src/test/java/org/zerodds/rtps/RpcDiscoveryTest.java (theThreeParametersTravelWithTheEndpoint, aStringBeyondTheBoundIsRefused, aTopicCorrespondsByNameOrByAlias). Die Java-Laufzeit hält die Matching-Regel aus den angekündigten Endpunkten ein (1fddccd2b87b): ReplierImpl hält die Requests eines Clients zurück, dessen Reply-Reader der Reply-Writer nicht kennt (Figure 7.3, je Client); RequesterImpl sendet, wenn der Request-Reader der Instanz einen Reply-Writer nennt, den der Reply-Reader entdeckt hat (Figure 7.4). Ein Endpunkt ohne Ankündigung und eine Bindung ohne Discovery-Daten behalten das Matching nach dem Topic. Test: crates/rpc/tests/java/RpcRuntimeRoundtrip.java::overTheJavaPsm über crates/rpc/tests/java_rpc_runtime.rs::the_java_rpc_runtime_and_the_generated_services_run_together (braucht ein JDK; auf dem Mac und dem Linux-Testhost nicht gelaufen).

§7.6.2 Service: Request erst nach Discovery des Client-DataReader

Spec: §7.6.2, S. 51 — “A service must ensure that service-side DataWriter has discovered the client-side DataReader before a request is accepted by the service-side DataReader.”

Repo: crates/rpc/src/replier.rs::Replier::take_requests (hält Requests eines nicht vollständig entdeckten Clients zurück), crates/rpc/src/discovery_ext.rs::client_matching_complete (Figure 7.3), runtime/cpp/include/dds/rpc/base.hpp::client_matching_complete, runtime/java/src/main/java/org/zerodds/ddsrpc/ReplierImpl.java

Tests: crates/rpc/src/replier.rs::tests::an_enhanced_request_of_an_undiscovered_client_is_held, crates/rpc/src/replier.rs::tests::the_named_alternatives_release_a_request_of_an_undiscovered_client, crates/rpc/src/discovery_ext.rs::tests::the_service_unmasks_a_client_once_both_its_endpoints_are_discovered, crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together, crates/zerodds-c-api/tests/rpc_discovery.rs::the_extension_is_announced_read_and_decides_the_matching

Status: done — Rust (e305669e2c42) und C++ (17a3aef74360) halten einen Enhanced-Request zurück, bis der Reply-Reader des sendenden Clients entdeckt ist (Figure 7.3); ClientMatching::Hold ist die Vorgabe, Off und accept_unannounced sind benannte Alternativen. Die Rust-Laufzeit hält höchstens HELD_REQUESTS_MAX Requests, weitere zählt Replier::held_overflow. crates/java-omgdds schreibt und liest die PIDs 0x0080 bis 0x0082 (rtps/RpcDiscovery.java, DiscoveryData.buildEndpoint und parseEndpoint, Grenze string<256>: eine Ankündigung darüber wird abgewiesen wie im Decoder von crates/rtps; f65fb3965b5e). ZeroDdsParticipant kündigt service_instance_name an den Endpunkten des Dienstes und related_*_key an beiden Seiten an (9993349aff89). Tests: crates/java-omgdds/java/src/test/java/org/zerodds/rtps/RpcDiscoveryTest.java (theThreeParametersTravelWithTheEndpoint, aStringBeyondTheBoundIsRefused, aTopicCorrespondsByNameOrByAlias). Die Java-Laufzeit hält die Matching-Regel aus den angekündigten Endpunkten ein (1fddccd2b87b): ReplierImpl hält die Requests eines Clients zurück, dessen Reply-Reader der Reply-Writer nicht kennt (Figure 7.3, je Client); RequesterImpl sendet, wenn der Request-Reader der Instanz einen Reply-Writer nennt, den der Reply-Reader entdeckt hat (Figure 7.4). Ein Endpunkt ohne Ankündigung und eine Bindung ohne Discovery-Daten behalten das Matching nach dem Topic. Test: crates/rpc/tests/java/RpcRuntimeRoundtrip.java::overTheJavaPsm über crates/rpc/tests/java_rpc_runtime.rs::the_java_rpc_runtime_and_the_generated_services_run_together (braucht ein JDK; auf dem Mac und dem Linux-Testhost nicht gelaufen).

§7.6.2.1 Erweiterte Typen der eingebauten Topics

Spec: §7.6.2.1, S. 51 — “This specification extends both PublicationBuiltinTopicData and SubscriptionBuiltinTopicData.” Dazu die Design Rationale zur ParameterList.

Repo: —

Tests: —

Status: n/a (informative) — Einleitung; die Member stehen in §7.6.2.1.1 und §7.6.2.1.2.

§7.6.2.1.1 service_instance_name mit PID 0x0080

Spec: §7.6.2.1.1, S. 51 — “service_instance_name string<256> PID_SERVICE_INSTANCE_NAME 0x0080”.

Repo: crates/rtps/src/parameter_list.rs (pid::SERVICE_INSTANCE_NAME), crates/rtps/src/publication_data.rs (PublicationBuiltinTopicData::service_instance_name, Codec), crates/dcps/src/runtime.rs::RpcDiscoveryExt::check (Grenze 256)

Tests: crates/rtps/src/parameter_list.rs::tests::rpc_pid_constants_match_spec, crates/rtps/src/publication_data.rs::tests::rpc_discovery_pids_roundtrip, crates/dcps/tests/rpc_discovery_extension.rs::a_discovery_string_longer_than_256_is_refused

Status: done — PID 0x0080 mit CDR-String; DataWriter::set_rpc_discovery und DataReader::set_rpc_discovery weisen einen Namen über 256 Zeichen ab (DdsError::BadParameter). PID und Codec b5224bd70dbb, Ankündigung und Grenze 211d416cdda3. Der Decoder prüft die Grenze bei einer empfangenen Ankündigung nicht.

Spec: §7.6.2.1.1, S. 51 — “related_datareader_key GUID_t PID_RELATED_ENTITY_GUID 0x0081”.

Repo: crates/rtps/src/parameter_list.rs (pid::RELATED_ENTITY_GUID), crates/rtps/src/publication_data.rs (PublicationBuiltinTopicData::related_entity_guid), crates/rtps/src/subscription_data.rs (dasselbe Feld, §7.6.2.1.2)

Tests: crates/rtps/src/parameter_list.rs::tests::rpc_pid_constants_match_spec, crates/rtps/src/publication_data.rs::tests::rpc_discovery_pids_roundtrip, crates/rtps/src/subscription_data.rs::tests::rpc_discovery_pids_roundtrip_subscription

Status: done — PID 0x0081 mit 16 Oktetten GUID; das Feld heißt related_entity_guid und trägt related_datareader_key einer Publication und related_datawriter_key einer Subscription. b5224bd70dbb.

§7.6.2.1.1 topic_aliases mit PID 0x0082

Spec: §7.6.2.1.1, S. 51 — “topic_aliases sequence<string<256>> PID_TOPIC_ALIASES 0x0082”.

Repo: crates/rtps/src/parameter_list.rs (pid::TOPIC_ALIASES), crates/rtps/src/publication_data.rs (PublicationBuiltinTopicData::topic_aliases), crates/dcps/src/runtime.rs::RpcDiscoveryExt::check (Grenze 256 je Alias)

Tests: crates/rtps/src/parameter_list.rs::tests::rpc_pids_roundtrip_in_parameter_list, crates/rtps/src/publication_data.rs::tests::rpc_discovery_pids_roundtrip, crates/dcps/tests/topic_alias_matching.rs::a_reader_on_an_alias_matches_the_writer_over_the_wire

Status: done — PID 0x0082 mit einer Folge von Strings; set_rpc_discovery weist einen Alias über 256 Zeichen ab, und die Zuordnung der Endpunkte benutzt die Aliase (bdf9ab1e6caa; PID b5224bd70dbb, Ankündigung 211d416cdda3).

§7.6.2.1.1 PublicationBuiltinTopicDataExt

Spec: §7.6.2.1.1, S. 51 — “@extensibility(MUTABLE_EXTENSIBILITY) struct PublicationBuiltinTopicDataExt : PublicationBuiltinTopicData { @ID(0x0080) string<256> service_instance_name; @ID(0x0081) GUID_t related_datareader_key; @ID(0x0082) sequence<string<256>> topic_aliases; };”

Repo: crates/rtps/src/publication_data.rs::PublicationBuiltinTopicData (die drei Member als optionale Parameter der ParameterList), crates/dcps/src/runtime.rs::RpcDiscoveryExt

Tests: crates/rtps/src/publication_data.rs::tests::rpc_discovery_pids_roundtrip, crates/rtps/src/publication_data.rs::tests::rpc_pids_optional_legacy_peer_parses_ok, crates/dcps/tests/rpc_discovery_extension.rs::the_rpc_extension_of_a_writer_and_a_reader_reaches_the_matched_peer

Status: done — die Leitung trägt die drei Member; ein Peer ohne die Parameter wird gelesen, die Member sind dann None. Der Typ PublicationBuiltinTopicDataExt mit den Member-Namen der Spec steht in crates/rpc (nächstes Item). b5224bd70dbb, 211d416cdda3.

§7.6.2.1.1 Typ PublicationBuiltinTopicDataExt in crates/rpc

Spec: §7.6.2.1.1, S. 51 — wie oben.

Repo: crates/rpc/src/discovery_ext.rs::PublicationBuiltinTopicDataExt und SubscriptionBuiltinTopicDataExt (announcement, from_peer)

Tests: crates/rpc/src/discovery_ext.rs::tests::the_extension_carries_the_three_members_of_the_spec, crates/rpc/src/discovery_ext.rs::tests::an_absent_related_key_reads_as_guid_unknown

Status: done — die Typen haben die Member der Spec (service_instance_name, related_datareader_key bzw. related_datawriter_key, topic_aliases); service_name und mapping_profile sind entfernt. announcement() wandelt sie in die Ankündigung von crates/dcps. Requester und Replier bilden RpcDiscoveryExt unmittelbar mit denselben drei Membern und benutzen diese Typen nicht (e305669e2c42).

§7.6.2.1.1 service_instance_name: Name der Instanz am Service

Spec: §7.6.2.1.1, S. 52 — “The service_instance_name is the instance name specified by the user at the service-side. If none is specified, there is no default value.”

Repo: crates/rpc/src/replier.rs::Replier::from_topics (Name nur, wenn angegeben), crates/rpc/src/endpoint.rs::RpcEndpointBuilder::instance_name, runtime/cpp/include/dds/rpc.hpp, runtime/java/src/main/java/org/zerodds/ddsrpc/ReplierImpl.java

Tests: crates/rpc-rust-e2e/tests/enhanced_e2e.rs::the_client_waits_for_the_service_instance_it_names, crates/rpc-rust-e2e/tests/evolution_styles_discovery.rs::the_runtime_announces_aliases_the_instance_name_and_the_related_keys, crates/rpc-rust-e2e/tests/evolution_styles_discovery.rs::a_service_without_an_instance_name_or_parents_announces_neither, crates/rpc/src/endpoint.rs::tests::instance_name_propagated_to_both_sides, crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together (rpc_runtime_roundtrip.cpp, check_instance_addressing)

Status: done — Rust (e305669e2c42, Tests 32972ee16bdd, 414e077c527d) und C++ (17a3aef74360) kündigen den Namen an den Service-Endpunkten an, wenn der Benutzer einen angibt; ohne Namen wird nichts angekündigt (Test dafür vorhanden). In C++ erreicht ein an eine Instanz gebundener Enhanced-Request nur Reader, die diesen Namen angekündigt haben (6289b73b7853). crates/java-omgdds schreibt und liest die PIDs 0x0080 bis 0x0082 (rtps/RpcDiscovery.java, DiscoveryData.buildEndpoint und parseEndpoint, Grenze string<256>: eine Ankündigung darüber wird abgewiesen wie im Decoder von crates/rtps; f65fb3965b5e). ZeroDdsParticipant kündigt service_instance_name an den Endpunkten des Dienstes und related_*_key an beiden Seiten an (9993349aff89). Tests: crates/java-omgdds/java/src/test/java/org/zerodds/rtps/RpcDiscoveryTest.java (theThreeParametersTravelWithTheEndpoint, aStringBeyondTheBoundIsRefused, aTopicCorrespondsByNameOrByAlias). Die Java-Laufzeit hält die Matching-Regel aus den angekündigten Endpunkten ein (1fddccd2b87b): ReplierImpl hält die Requests eines Clients zurück, dessen Reply-Reader der Reply-Writer nicht kennt (Figure 7.3, je Client); RequesterImpl sendet, wenn der Request-Reader der Instanz einen Reply-Writer nennt, den der Reply-Reader entdeckt hat (Figure 7.4). Ein Endpunkt ohne Ankündigung und eine Bindung ohne Discovery-Daten behalten das Matching nach dem Topic. Test: crates/rpc/tests/java/RpcRuntimeRoundtrip.java::overTheJavaPsm über crates/rpc/tests/java_rpc_runtime.rs::the_java_rpc_runtime_and_the_generated_services_run_together (braucht ein JDK; auf dem Mac und dem Linux-Testhost nicht gelaufen).

§7.6.2.1.1 Client-DataWriter ohne service_instance_name

Spec: §7.6.2.1.1, S. 52 — “Likewise, the client-side DataWriter shall not include service_instance_name.”

Repo: crates/rpc/src/requester.rs::Requester::from_topics (service_instance_name: None), crates/rpc/src/endpoint.rs::RpcEndpointBuilder::publication (nur auf der Service-Seite)

Tests: crates/rpc/src/endpoint.rs::tests::instance_name_propagated_to_both_sides (prüft den Builder; der Name des Tests stammt aus dem früheren Verhalten), crates/rpc-rust-e2e/tests/enhanced_e2e.rs::the_client_waits_for_the_service_instance_it_names, crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together

Status: done — der Client-Writer kündigt keinen service_instance_name an, in Rust, C++ (Test: request_writer.has_instance_name ist falsch) und Java (der Client erhält keinen Namen). 973def296a10 (Builder), e305669e2c42 (Laufzeit). Kein Rust-Test liest die Ankündigung eines Requester von der Gegenstelle zurück.

§7.6.2.1.1 topic_aliases nach §7.4.3, ohne Vorgabe

Spec: §7.6.2.1.1, S. 52 — “The topic_aliases are as per defined in 7.4.3 The Enhanced Service Mapping. There is no default value.”

Repo: crates/rpc/src/requester.rs::Requester::from_topics, crates/rpc/src/replier.rs::Replier::from_topics (Aliase aus ServiceTopicNames::request_aliases und reply_aliases), crates/rpc/src/endpoint.rs::RpcEndpointBuilder::aliases

Tests: crates/rpc/src/topic_naming.rs::tests::every_parent_interface_contributes_one_alias, crates/rpc/src/endpoint.rs::tests::the_parent_interfaces_are_announced_as_topic_aliases, crates/rpc/src/endpoint.rs::tests::topic_aliases_empty_yields_none, crates/rpc-rust-e2e/tests/evolution_styles_discovery.rs::the_runtime_announces_aliases_the_instance_name_and_the_related_keys, crates/rpc-rust-e2e/tests/evolution_styles_discovery.rs::a_service_without_an_instance_name_or_parents_announces_neither, crates/dcps/tests/rpc_discovery_extension.rs::the_rpc_extension_of_a_writer_and_a_reader_reaches_the_matched_peer, crates/rpc-rust-e2e/tests/java_peer.rs::a_java_client_calls_a_rust_service, crates/rpc-rust-e2e/tests/java_peer.rs::a_rust_client_calls_a_java_service, crates/rpc-rust-e2e/tests/java_peer.rs::a_java_client_of_the_base_calls_a_rust_service_of_the_derived_interface, crates/rpc-rust-e2e/tests/java_peer.rs::a_rust_client_of_the_base_calls_a_java_service_of_the_derived_interface

Status: done — Rust (e305669e2c42) und C++ kündigen die Aliase der Elternteile an (§7.4.3), ohne Eltern und ohne Angabe nichts. Ein laufender Requester und Replier kündigt die Aliase an, die Gegenstelle liest sie; ohne Eltern bleibt das Feld leer (Tests oben, 32972ee16bdd, 414e077c527d). Java kündigt die Aliase an, die parents der Params ergeben (PID 0x0082 auf der Leitung: RpcDiscoveryTest.java::theThreeParametersTravelWithTheEndpoint, f65fb3965b5e, 9993349aff89); die erzeugte Java-Bindung setzt parents für ein abgeleitetes Interface (400433a9d00a). Die Java-PSM ordnet über die Aliase zu und paart die Typen nach Zuweisbarkeit (2d0f809c6e2); gemessen mit einem Java-Client der Basis gegen einen Rust-Dienst des abgeleiteten Interface und umgekehrt (Item zu §7.4.3, Java).

Spec: §7.6.2.1.1, S. 52 — “When not present the default value for the related_datareader_key shall be interpreted as GUID_UNKNOWN as defined by sub clause 9.3.1.5 of the [RTPS] specification.”

Repo: crates/rpc/src/discovery_ext.rs::GUID_UNKNOWN und from_peer, crates/rtps/src/publication_data.rs (der Decoder liefert None)

Tests: crates/rpc/src/discovery_ext.rs::tests::an_absent_related_key_reads_as_guid_unknown, crates/rpc/src/discovery_ext.rs::tests::an_unannounced_service_completes_only_when_accepted, crates/rtps/src/publication_data.rs::tests::rpc_pids_optional_legacy_peer_parses_ok

Status: done — ein fehlender Schlüssel liest sich als GUID_UNKNOWN (16 Nullen); die Matching-Funktionen behandeln ihn als nicht genannt, ein Paar ohne Nennung ist nur mit accept_unannounced vollständig (e305669e2c42).

Spec: §7.6.2.1.1, S. 52 — “The PublicationBuiltinTopicDataExt that corresponds to the client-side DataWriter used for sending requests for a service shall have the related_datareader_key set to the BuiltinTopicKey_t of the client-side DataReader used for receiving the replies.”

Repo: crates/rpc/src/requester.rs::Requester::from_topics (set_rpc_discovery am Request-Writer mit der GUID des Reply-Readers), crates/rpc/src/endpoint.rs::RpcEndpointBuilder::build_requester

Tests: crates/rpc/src/endpoint.rs::tests::requester_related_entity_guids_cross_link, crates/rpc-rust-e2e/tests/evolution_styles_discovery.rs::the_runtime_announces_aliases_the_instance_name_and_the_related_keys, crates/rpc-rust-e2e/tests/enhanced_e2e.rs::the_client_waits_for_the_service_instance_it_names, crates/zerodds-c-api/tests/rpc_discovery.rs::the_extension_is_announced_read_and_decides_the_matching

Status: done — Rust (e305669e2c42) und C++ (17a3aef74360) setzen den Schlüssel am Client-Writer auf den Reply-Reader und umgekehrt. Der Rust-Test the_runtime_announces_aliases_the_instance_name_and_the_related_keys liest die Schlüssel an den Gegenstellen eines laufenden Requester und Replier (32972ee16bdd, 414e077c527d). crates/java-omgdds schreibt und liest die PIDs 0x0080 bis 0x0082 (rtps/RpcDiscovery.java, DiscoveryData.buildEndpoint und parseEndpoint, Grenze string<256>: eine Ankündigung darüber wird abgewiesen wie im Decoder von crates/rtps; f65fb3965b5e). ZeroDdsParticipant kündigt service_instance_name an den Endpunkten des Dienstes und related_*_key an beiden Seiten an (9993349aff89). Tests: crates/java-omgdds/java/src/test/java/org/zerodds/rtps/RpcDiscoveryTest.java (theThreeParametersTravelWithTheEndpoint, aStringBeyondTheBoundIsRefused, aTopicCorrespondsByNameOrByAlias). Die Java-Laufzeit hält die Matching-Regel aus den angekündigten Endpunkten ein (1fddccd2b87b): ReplierImpl hält die Requests eines Clients zurück, dessen Reply-Reader der Reply-Writer nicht kennt (Figure 7.3, je Client); RequesterImpl sendet, wenn der Request-Reader der Instanz einen Reply-Writer nennt, den der Reply-Reader entdeckt hat (Figure 7.4). Ein Endpunkt ohne Ankündigung und eine Bindung ohne Discovery-Daten behalten das Matching nach dem Topic. Test: crates/rpc/tests/java/RpcRuntimeRoundtrip.java::overTheJavaPsm über crates/rpc/tests/java_rpc_runtime.rs::the_java_rpc_runtime_and_the_generated_services_run_together (braucht ein JDK; auf dem Mac und dem Linux-Testhost nicht gelaufen).

Spec: §7.6.2.1.1, S. 52 — “The PublicationBuiltinTopicDataExt that corresponds to the service-side DataWriter used for sending replies shall have the related_datareader_key set to the BuiltinTopicKey_t of the service-side DataReader used to receive the requests.”

Repo: crates/rpc/src/replier.rs::Replier::from_topics (set_rpc_discovery am Reply-Writer mit der GUID des Request-Readers), crates/rpc/src/endpoint.rs::RpcEndpointBuilder::build_replier

Tests: crates/rpc/src/endpoint.rs::tests::replier_related_entity_guids_cross_link, crates/rpc-rust-e2e/tests/enhanced_e2e.rs::the_client_waits_for_the_service_instance_it_names, crates/zerodds-c-api/tests/rpc_discovery.rs::the_extension_is_announced_read_and_decides_the_matching, crates/rpc-rust-e2e/tests/evolution_styles_discovery.rs::the_runtime_announces_aliases_the_instance_name_and_the_related_keys

Status: done — Rust (e305669e2c42) und C++ (17a3aef74360) setzen den Schlüssel am Service-Writer auf den Request-Reader und umgekehrt. Für Rust liest ein Test die Ankündigung des Replier an der Gegenseite: related_entity_guid des Reply-Writers ist die GUID des Request-Readers (414e077c527d). crates/java-omgdds schreibt und liest die PIDs 0x0080 bis 0x0082 (rtps/RpcDiscovery.java, DiscoveryData.buildEndpoint und parseEndpoint, Grenze string<256>: eine Ankündigung darüber wird abgewiesen wie im Decoder von crates/rtps; f65fb3965b5e). ZeroDdsParticipant kündigt service_instance_name an den Endpunkten des Dienstes und related_*_key an beiden Seiten an (9993349aff89). Tests: crates/java-omgdds/java/src/test/java/org/zerodds/rtps/RpcDiscoveryTest.java (theThreeParametersTravelWithTheEndpoint, aStringBeyondTheBoundIsRefused, aTopicCorrespondsByNameOrByAlias). Die Java-Laufzeit hält die Matching-Regel aus den angekündigten Endpunkten ein (1fddccd2b87b): ReplierImpl hält die Requests eines Clients zurück, dessen Reply-Reader der Reply-Writer nicht kennt (Figure 7.3, je Client); RequesterImpl sendet, wenn der Request-Reader der Instanz einen Reply-Writer nennt, den der Reply-Reader entdeckt hat (Figure 7.4). Ein Endpunkt ohne Ankündigung und eine Bindung ohne Discovery-Daten behalten das Matching nach dem Topic. Test: crates/rpc/tests/java/RpcRuntimeRoundtrip.java::overTheJavaPsm über crates/rpc/tests/java_rpc_runtime.rs::the_java_rpc_runtime_and_the_generated_services_run_together (braucht ein JDK; auf dem Mac und dem Linux-Testhost nicht gelaufen).

§7.6.2.1.2 service_instance_name mit PID 0x0080

Spec: §7.6.2.1.2, S. 52 — “service_instance_name string<256> PID_SERVICE_INSTANCE_NAME 0x0080”.

Repo: crates/rtps/src/parameter_list.rs (pid::SERVICE_INSTANCE_NAME); crates/rtps/src/subscription_data.rs (SubscriptionBuiltinTopicData::service_instance_name, Codec in to_pl_cdr_le und from_pl_cdr_le); crates/dcps/src/subscriber.rs (DataReader::set_rpc_discovery, DataReader::matched_rpc_writers) mit RpcDiscoveryExt in crates/dcps/src/runtime.rs

Tests: crates/rtps/src/subscription_data.rs::tests::rpc_discovery_pids_roundtrip_subscription, crates/rtps/src/parameter_list.rs::tests::rpc_pid_constants_match_spec, crates/dcps/tests/rpc_discovery_extension.rs::the_rpc_extension_of_a_writer_and_a_reader_reaches_the_matched_peer (nur Linux)

Status: done — PID 0x0080 wird kodiert, dekodiert und vom DataReader angekündigt (Codec b5224bd70dbb, Ankündigung 211d416cdda3). RpcDiscoveryExt::check (crates/dcps/src/runtime.rs) weist beim Ankündigen eine Zeichenkette über 256 zurück (Test: crates/dcps/tests/rpc_discovery_extension.rs::a_discovery_string_longer_than_256_is_refused). Der Decoder in crates/rtps lehnt einen Wert über 256 mit WireError::ValueOutOfRange ab (ae5fededca89; Test: crates/rtps/src/subscription_data.rs::tests::a_discovery_string_beyond_the_bound_is_refused_subscription).

Spec: §7.6.2.1.2, S. 52 — “related_datawriter_key GUID_t PID_RELATED_ENTITY_GUID 0x0081”.

Repo: crates/rtps/src/parameter_list.rs (pid::RELATED_ENTITY_GUID); crates/rtps/src/subscription_data.rs (SubscriptionBuiltinTopicData::related_entity_guid, Codec in to_pl_cdr_le und from_pl_cdr_le); crates/dcps/src/subscriber.rs (DataReader::set_rpc_discovery, DataReader::matched_rpc_writers) mit RpcDiscoveryExt in crates/dcps/src/runtime.rs

Tests: crates/rtps/src/subscription_data.rs::tests::rpc_discovery_pids_roundtrip_subscription, crates/rtps/src/parameter_list.rs::tests::rpc_pid_constants_match_spec, crates/dcps/tests/rpc_discovery_extension.rs::the_rpc_extension_of_a_writer_and_a_reader_reaches_the_matched_peer (nur Linux)

Status: done — PID 0x0081 (PID_RELATED_ENTITY_GUID) wird kodiert, dekodiert und angekündigt (Codec b5224bd70dbb, Ankündigung 211d416cdda3). Das Feld heißt im Code related_entity_guid; beim DataReader ist es der related_datawriter_key.

§7.6.2.1.2 topic_aliases mit PID 0x0082

Spec: §7.6.2.1.2, S. 52 — “topic_aliases sequence<string<256>> PID_TOPIC_ALIASES 0x0082”.

Repo: crates/rtps/src/parameter_list.rs (pid::TOPIC_ALIASES); crates/rtps/src/subscription_data.rs (SubscriptionBuiltinTopicData::topic_aliases, Codec in to_pl_cdr_le und from_pl_cdr_le); crates/dcps/src/subscriber.rs (DataReader::set_rpc_discovery, DataReader::matched_rpc_writers) mit RpcDiscoveryExt in crates/dcps/src/runtime.rs

Tests: crates/rtps/src/subscription_data.rs::tests::rpc_discovery_pids_roundtrip_subscription, crates/rtps/src/parameter_list.rs::tests::rpc_pid_constants_match_spec, crates/dcps/tests/rpc_discovery_extension.rs::the_rpc_extension_of_a_writer_and_a_reader_reaches_the_matched_peer (nur Linux)

Status: done — PID 0x0082 wird kodiert (Folge von Zeichenketten), dekodiert und angekündigt (Codec b5224bd70dbb, Ankündigung 211d416cdda3). Das Matching nach Alias steht beim Item zu §7.4.3.

§7.6.2.1.2 SubscriptionBuiltinTopicDataExt

Spec: §7.6.2.1.2, S. 52 — “@extensibility(MUTABLE_EXTENSIBILITY) struct SubscriptionBuiltinTopicDataExt : SubscriptionBuiltinTopicData { @ID(0x0080) string<256> service_instance_name; @ID(0x0081) GUID_t related_datawriter_key; @ID(0x0082) sequence<string<256>> topic_aliases; };”

Repo: crates/rtps/src/subscription_data.rs::SubscriptionBuiltinTopicData (Wire); crates/rpc/src/discovery_ext.rs::SubscriptionBuiltinTopicDataExt (Datenmodell mit den drei Members der Spec, announcement und from_peer zu zerodds_dcps::runtime::RpcDiscoveryExt)

Tests: crates/rtps/src/subscription_data.rs::tests::rpc_discovery_pids_roundtrip_subscription, crates/rtps/src/subscription_data.rs::tests::rpc_pids_optional_legacy_subscription_parses_ok, crates/rpc/src/discovery_ext.rs::tests::the_extension_carries_the_three_members_of_the_spec

Status: done — der Typ in crates/rpc hat die drei Members der Spec (service_instance_name, related_datawriter_key, topic_aliases); auf der Leitung stehen sie als Parameter 0x0080 bis 0x0082 der Parameterliste (Typ in crates/rpc e305669e2c42, Wire b5224bd70dbb). Ein Endpunkt ohne die Parameter wird gelesen und liefert None bzw. GUID_UNKNOWN.

§7.6.2.1.2 service_instance_name: Name der Instanz am Service

Spec: §7.6.2.1.2, S. 52 — “The service_instance_name is the instance name specified by the user at the service-side. If none is specified, there is no default value.”

Repo: crates/rpc/src/replier.rs::Replier::with_options (Enhanced: der Name der Instanz geht an Request-Reader und Reply-Writer, ohne Namen entfällt der Wert); crates/rpc/src/endpoint.rs::RpcEndpointBuilder::instance_name

Tests: crates/rpc/src/endpoint.rs::tests::instance_name_propagated_to_both_sides, crates/rpc-rust-e2e/tests/enhanced_e2e.rs::the_client_waits_for_the_service_instance_it_names

Status: done — der Service kündigt den vom Nutzer gesetzten Namen an, ohne Namen None (e305669e2c42). Der Test zeigt, dass der Client nur die Instanz erreicht, deren Namen er trägt. C++ kündigt denselben Wert an (17a3aef74360; Test: crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together). Java siehe Item „§7.6.2.1 Ankündigung der Erweiterungen durch die Laufzeiten“.

§7.6.2.1.2 Client-DataReader ohne service_instance_name

Spec: §7.6.2.1.2, S. 52 — “Likewise, the client-side DataReader shall not include service_instance_name.”

Repo: crates/rpc/src/requester.rs::Requester::with_options (Enhanced: service_instance_name: None an Request-Writer und Reply-Reader); crates/rpc/src/endpoint.rs::RpcEndpointBuilder (973def296a10)

Tests: crates/rpc/src/endpoint.rs::tests::instance_name_propagated_to_both_sides (Builder); C++: crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together, crates/rpc-rust-e2e/tests/evolution_styles_discovery.rs::the_runtime_announces_aliases_the_instance_name_and_the_related_keys

Status: done — der Reply-Reader des Requesters kündigt in Rust (e305669e2c42), C++ (17a3aef74360) und im Builder (973def296a10) keinen Namen an. Für Rust liest ein Test die Ankündigung von Requester und Replier an der Gegenseite (matched_rpc_readers, matched_rpc_writers): die Endpunkte des Clients tragen service_instance_name: None (414e077c527d). crates/java-omgdds schreibt und liest die PIDs 0x0080 bis 0x0082 (rtps/RpcDiscovery.java, DiscoveryData.buildEndpoint und parseEndpoint, Grenze string<256>: eine Ankündigung darüber wird abgewiesen wie im Decoder von crates/rtps; f65fb3965b5e). ZeroDdsParticipant kündigt service_instance_name an den Endpunkten des Dienstes und related_*_key an beiden Seiten an (9993349aff89). Tests: crates/java-omgdds/java/src/test/java/org/zerodds/rtps/RpcDiscoveryTest.java (theThreeParametersTravelWithTheEndpoint, aStringBeyondTheBoundIsRefused, aTopicCorrespondsByNameOrByAlias). Die Java-Laufzeit hält die Matching-Regel aus den angekündigten Endpunkten ein (1fddccd2b87b): ReplierImpl hält die Requests eines Clients zurück, dessen Reply-Reader der Reply-Writer nicht kennt (Figure 7.3, je Client); RequesterImpl sendet, wenn der Request-Reader der Instanz einen Reply-Writer nennt, den der Reply-Reader entdeckt hat (Figure 7.4). Ein Endpunkt ohne Ankündigung und eine Bindung ohne Discovery-Daten behalten das Matching nach dem Topic. Test: crates/rpc/tests/java/RpcRuntimeRoundtrip.java::overTheJavaPsm über crates/rpc/tests/java_rpc_runtime.rs::the_java_rpc_runtime_and_the_generated_services_run_together (braucht ein JDK; auf dem Mac und dem Linux-Testhost nicht gelaufen).

§7.6.2.1.2 topic_aliases nach §7.4.3, ohne Vorgabe

Spec: §7.6.2.1.2, S. 52 — “The topic_aliases are as per defined in sub clause 7.4.3. There is no default value.”

Repo: crates/rpc/src/requester.rs::Requester::with_options und crates/rpc/src/replier.rs::Replier::with_options (Aliase aus ServiceTopicNames::request_aliases und reply_aliases, ohne Aliase None); crates/rpc/src/endpoint.rs::RpcEndpointBuilder (aliases); crates/dcps/src/runtime.rs (Matching nach Alias)

Tests: crates/rpc/src/endpoint.rs::tests::topic_aliases_propagated_to_both_sides, crates/dcps/tests/topic_alias_matching.rs (nur Linux), crates/dcps/tests/rpc_discovery_extension.rs::the_rpc_extension_of_a_writer_and_a_reader_reaches_the_matched_peer, crates/rpc/tests/language_binding_agreement.rs (Namen der Aliase); C++: crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together, crates/rpc-rust-e2e/tests/evolution_styles_discovery.rs::the_runtime_announces_aliases_the_instance_name_and_the_related_keys, crates/rpc-rust-e2e/tests/evolution_styles_discovery.rs::a_service_without_an_instance_name_or_parents_announces_neither, crates/rpc-rust-e2e/tests/java_peer.rs::a_java_client_calls_a_rust_service, crates/rpc-rust-e2e/tests/java_peer.rs::a_rust_client_calls_a_java_service, crates/rpc-rust-e2e/tests/java_peer.rs::a_java_client_of_the_base_calls_a_rust_service_of_the_derived_interface, crates/rpc-rust-e2e/tests/java_peer.rs::a_rust_client_of_the_base_calls_a_java_service_of_the_derived_interface

Status: done — die Aliase gehen bei Vererbung auf die Leitung (Rust e305669e2c42, C++ 17a3aef74360) und lassen Endpunkte matchen (bdf9ab1e6caa); ohne Aliase wird nichts angekündigt. Für Rust liest ein Test die Aliase von Requester und Replier an der Gegenseite (robot_Base_Service_Request und robot_Base_Service_Reply) und prüft, dass ein Service ohne Basis keine Aliase ankündigt (414e077c527d). Java kündigt die Aliase an, die parents der Params ergeben (f65fb3965b5e, 9993349aff89); die erzeugte Java-Bindung setzt parents für ein abgeleitetes Interface (400433a9d00a). Die Java-PSM ordnet über die Aliase zu und paart die Typen nach Zuweisbarkeit (2d0f809c6e2); gemessen mit einem Java-Client der Basis gegen einen Rust-Dienst des abgeleiteten Interface und umgekehrt (Item zu §7.4.3, Java).

Spec: §7.6.2.1.2, S. 53 — “When not present the default value for the related_datareader_key shall be interpreted as GUID_UNKNOWN as defined by sub clause 9.3.1.5 of the [RTPS] specification.”

Repo: crates/rpc/src/discovery_ext.rs::SubscriptionBuiltinTopicDataExt::from_peer (GUID_UNKNOWN); crates/rtps/src/subscription_data.rs (der Decoder liefert None)

Tests: crates/rtps/src/subscription_data.rs::tests::rpc_pids_optional_legacy_subscription_parses_ok, crates/rpc/src/discovery_ext.rs::tests::an_absent_related_key_reads_as_guid_unknown, crates/rpc/src/discovery_ext.rs::tests::an_unannounced_service_completes_only_when_accepted

Status: done — ein fehlender Parameter 0x0081 liest als GUID_UNKNOWN (e305669e2c42). Der Abschnitt der Spec über die Subscription nennt hier related_datareader_key.

Spec: §7.6.2.1.2, S. 53 — “The SubscriptionBuiltinTopicDataExt that corresponds to the client-side DataReader used to receive replies shall have the related_datawriter_key set to the BuiltinTopicKey_t of the client-side DataWriter used to send the requests to the DDS-RPC Service.”

Repo: crates/rpc/src/requester.rs::Requester::with_options (Reply-Reader nennt den Request-Writer); crates/rpc/src/endpoint.rs::RpcEndpointBuilder::build_requester

Tests: crates/rpc-rust-e2e/tests/enhanced_e2e.rs::an_enhanced_call_is_answered_through_the_related_sample_identity, crates/rpc/src/endpoint.rs::tests::requester_related_entity_guids_cross_link, crates/rpc/src/discovery_ext.rs::tests::the_service_unmasks_a_client_once_both_its_endpoints_are_discovered

Status: done — Rust e305669e2c42, C++ 17a3aef74360. Der Aufruf im ersten Test wird nur beantwortet, wenn der Service den Reply-Reader des Clients über related_datawriter_key dem Request-Writer zuordnen kann (client_matching_complete, Standardeinstellung ClientMatching::Hold).

Spec: §7.6.2.1.2, S. 53 — “The SubscriptionBuiltinTopicDataExt that corresponds to the service-side DataReader used to write replies shall have the related_datawriter_key set to the BuiltinTopicKey_t of the service-side DataWriter used to receive requests.”

Repo: crates/rpc/src/replier.rs::Replier::with_options (Request-Reader nennt den Reply-Writer); crates/rpc/src/endpoint.rs::RpcEndpointBuilder::build_replier

Tests: crates/rpc-rust-e2e/tests/enhanced_e2e.rs::the_client_waits_for_the_service_instance_it_names, crates/rpc/src/endpoint.rs::tests::replier_related_entity_guids_cross_link, crates/rpc/src/discovery_ext.rs::tests::the_two_endpoints_must_name_each_other

Status: done — Rust e305669e2c42, C++ 17a3aef74360. Der Satz der Spec vertauscht die Rollen („DataReader used to write replies“, „DataWriter used to receive requests“); der Request-Reader nennt den Reply-Writer, wie Figure 7.4 es verlangt. service_matching_complete ist nur erfüllt, wenn Request-Reader und Reply-Writer einander nennen (Test 1 und 3).

§7.6.2.1 Ankündigung der Erweiterungen durch die Laufzeiten

Spec: §7.6.2.1.1 und §7.6.2.1.2, S. 51–53 — wie die Items oben.

Repo: crates/dcps/src/publisher.rs und crates/dcps/src/subscriber.rs (set_rpc_discovery, matched_rpc_readers, matched_rpc_writers); crates/rpc/src/requester.rs::Requester::with_options und crates/rpc/src/replier.rs::Replier::with_options (Enhanced); C++: runtime/cpp/include/dds/rpc.hpp (announce_rpc_discovery) und runtime/cpp/include/dds/rpc/zerodds.hpp über zerodds_writer_set_rpc_discovery und zerodds_reader_set_rpc_discovery (crates/zerodds-c-api/src/rpc_discovery_ffi.rs)

Tests: crates/dcps/tests/rpc_discovery_extension.rs::the_rpc_extension_of_a_writer_and_a_reader_reaches_the_matched_peer (nur Linux), crates/zerodds-c-api/tests/rpc_discovery.rs::the_extension_is_announced_read_and_decides_the_matching, crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together, crates/rpc-rust-e2e/tests/enhanced_e2e.rs::the_client_waits_for_the_service_instance_it_names, crates/rpc-rust-e2e/tests/evolution_styles_discovery.rs::the_runtime_announces_aliases_the_instance_name_and_the_related_keys, crates/rpc-rust-e2e/tests/evolution_styles_discovery.rs::a_service_without_an_instance_name_or_parents_announces_neither, crates/rpc-rust-e2e/tests/java_peer.rs::a_java_client_calls_a_rust_service, crates/rpc-rust-e2e/tests/java_peer.rs::a_rust_client_calls_a_java_service, crates/rpc-rust-e2e/tests/java_peer.rs::a_java_client_of_the_base_calls_a_rust_service_of_the_derived_interface, crates/rpc-rust-e2e/tests/java_peer.rs::a_rust_client_of_the_base_calls_a_java_service_of_the_derived_interface

Status: done — Rust, C++ und Java kündigen service_instance_name, related_*_key und topic_aliases ihrer Endpunkte an und lesen sie bei entdeckten Endpunkten (dcps 211d416cdda3, Rust e305669e2c42, C++ 17a3aef74360, Java f65fb3965b5e und 9993349aff89); die Grenze 256 prüft RpcDiscoveryExt::check beim Ankündigen, der Decoder in crates/rtps und der von crates/java-omgdds lehnen Werte darüber ab (ae5fededca89, f65fb3965b5e). Für Rust liest ein Test die Ankündigung von Requester und Replier an der Gegenseite (414e077c527d), für Java RpcDiscoveryTest.java. Die erzeugte Java-Bindung setzt die Aliase eines abgeleiteten Interface (400433a9d00a); ein Java-Peer gegen einen Rust-Peer liest die Ankündigung (dbb935492284). Die Java-PSM ordnet über die gelesenen Aliase zu und paart nach der Zuweisbarkeit (2d0f809c6e2), gemessen gegen Rust-Peers in beiden Richtungen (Item zu §7.4.3, Java).

§7.6.2.2 Zusätzliche Regeln an Client-Writer und Service-Reader

Spec: §7.6.2.2, S. 53 — “Additional rules shall be used at the client-side DataWriter and service-side DataReader”.

Repo: —

Tests: —

Status: n/a (informative) — Einleitung; die Regeln folgen als Items.

§7.6.2.2 Client-Writer sendet erst nach dem Matching des Reply-Writers

Spec: §7.6.2.2, S. 53 — “The client-side DataWriter (request DataWriter) shall not send out any request to a service DataReader unless the client-side DataReader (reply DataReader) has discovered and matched the corresponding service DataWriter (reply DataWriter).”

Repo: crates/rpc/src/requester.rs::Requester::service_matched und Requester::wait_for_service (Enhanced); crates/rpc/src/discovery_ext.rs::service_matching_complete; C++: runtime/cpp/include/dds/rpc.hpp (Requester::wait_for_service, DataWriter::service_matching_complete); Java: runtime/java/src/main/java/org/zerodds/ddsrpc/RequesterImpl.java

Tests: crates/rpc/src/requester.rs::tests::an_enhanced_request_waits_for_the_service_and_fails_without_sending, crates/rpc/src/requester.rs::tests::the_fail_setting_does_not_wait, crates/rpc/src/requester.rs::tests::the_basic_mapping_sends_without_a_service_match, crates/rpc-rust-e2e/tests/enhanced_e2e.rs::the_client_waits_for_the_service_instance_it_names, crates/rpc/src/discovery_ext.rs::tests::the_client_waits_for_both_service_endpoints, crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together, crates/rpc/tests/java_rpc_runtime.rs::the_java_rpc_runtime_and_the_generated_services_run_together

Status: done — Rust (e305669e2c42) und C++ (4b6b049312ff, 17a3aef74360): der Request geht erst hinaus, wenn Request-Reader und Reply-Writer des Services entdeckt sind und einander nennen. Der Rust-Aufruf hält den Request bis höchstens request_timeout der QoS und endet danach mit RpcError::ServiceNotMatched, ohne gesendet zu haben (ServiceMatching::Queue; Fail und Off sind die benannten Alternativen). Die Basic-Abbildung hat die Regel nicht (§7.6.1). crates/java-omgdds schreibt und liest die PIDs 0x0080 bis 0x0082 (rtps/RpcDiscovery.java, DiscoveryData.buildEndpoint und parseEndpoint, Grenze string<256>: eine Ankündigung darüber wird abgewiesen wie im Decoder von crates/rtps; f65fb3965b5e). ZeroDdsParticipant kündigt service_instance_name an den Endpunkten des Dienstes und related_*_key an beiden Seiten an (9993349aff89). Tests: crates/java-omgdds/java/src/test/java/org/zerodds/rtps/RpcDiscoveryTest.java (theThreeParametersTravelWithTheEndpoint, aStringBeyondTheBoundIsRefused, aTopicCorrespondsByNameOrByAlias). Die Java-Laufzeit hält die Matching-Regel aus den angekündigten Endpunkten ein (1fddccd2b87b): ReplierImpl hält die Requests eines Clients zurück, dessen Reply-Reader der Reply-Writer nicht kennt (Figure 7.3, je Client); RequesterImpl sendet, wenn der Request-Reader der Instanz einen Reply-Writer nennt, den der Reply-Reader entdeckt hat (Figure 7.4). Ein Endpunkt ohne Ankündigung und eine Bindung ohne Discovery-Daten behalten das Matching nach dem Topic. Test: crates/rpc/tests/java/RpcRuntimeRoundtrip.java::overTheJavaPsm über crates/rpc/tests/java_rpc_runtime.rs::the_java_rpc_runtime_and_the_generated_services_run_together (braucht ein JDK; auf dem Mac und dem Linux-Testhost nicht gelaufen).

§7.6.2.2 Service-Reader weist Requests vor dem Matching ab

Spec: §7.6.2.2, S. 53 — “The service-side DataReader (request DataReader) shall reject requests from a client DataWriter (request DataWriter) as long as the service-side DataWriter (reply DataWriter) has not discovered and matched the corresponding client-side DataReader (reply DataReader).”

Repo: crates/rpc/src/replier.rs::Replier::take_enhanced_requests (hält Requests eines Clients, der nicht vollständig entdeckt ist); crates/rpc/src/discovery_ext.rs::client_matching_complete; C++: runtime/cpp/include/dds/rpc.hpp (Replier, DataReader::client_matching_complete); Java: runtime/java/src/main/java/org/zerodds/ddsrpc/ReplierImpl.java

Tests: crates/rpc/src/replier.rs::tests::an_enhanced_request_of_an_undiscovered_client_is_held, crates/rpc/src/replier.rs::tests::the_named_alternatives_release_a_request_of_an_undiscovered_client, crates/rpc/src/discovery_ext.rs::tests::the_service_unmasks_a_client_once_both_its_endpoints_are_discovered, crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together, crates/rpc/tests/java_rpc_runtime.rs::the_java_rpc_runtime_and_the_generated_services_run_together

Status: done — Rust (e305669e2c42) und C++ (4b6b049312ff, 17a3aef74360): der Service bearbeitet keinen Request eines Clients, dessen Reply-Reader der Reply-Writer nicht entdeckt hat. Rust hält den Request (bis HELD_REQUESTS_MAX = 4096, der Überlauf wird in held_overflow() gezählt) und bearbeitet ihn, sobald der Client vollständig ist, statt ihn zu verwerfen. Die Basic-Abbildung hat die Regel nicht. crates/java-omgdds schreibt und liest die PIDs 0x0080 bis 0x0082 (rtps/RpcDiscovery.java, DiscoveryData.buildEndpoint und parseEndpoint, Grenze string<256>: eine Ankündigung darüber wird abgewiesen wie im Decoder von crates/rtps; f65fb3965b5e). ZeroDdsParticipant kündigt service_instance_name an den Endpunkten des Dienstes und related_*_key an beiden Seiten an (9993349aff89). Tests: crates/java-omgdds/java/src/test/java/org/zerodds/rtps/RpcDiscoveryTest.java (theThreeParametersTravelWithTheEndpoint, aStringBeyondTheBoundIsRefused, aTopicCorrespondsByNameOrByAlias). Die Java-Laufzeit hält die Matching-Regel aus den angekündigten Endpunkten ein (1fddccd2b87b): ReplierImpl hält die Requests eines Clients zurück, dessen Reply-Reader der Reply-Writer nicht kennt (Figure 7.3, je Client); RequesterImpl sendet, wenn der Request-Reader der Instanz einen Reply-Writer nennt, den der Reply-Reader entdeckt hat (Figure 7.4). Ein Endpunkt ohne Ankündigung und eine Bindung ohne Discovery-Daten behalten das Matching nach dem Topic. Test: crates/rpc/tests/java/RpcRuntimeRoundtrip.java::overTheJavaPsm über crates/rpc/tests/java_rpc_runtime.rs::the_java_rpc_runtime_and_the_generated_services_run_together (braucht ein JDK; auf dem Mac und dem Linux-Testhost nicht gelaufen).

§7.6.2.2 Umsetzung außerhalb der DDS-Schicht zulässig

Spec: §7.6.2.2, S. 53 — “The above rules may be implemented outside “DDS layer” because no discovery algorithm modifications are required in the underlying DDS implementation”.

Repo: —

Tests: —

Status: n/a (informative) — Erlaubnis.

§7.6.2.2.1 Client Matching am Service: keine Requests bis zum Abschluss

Spec: §7.6.2.2.1, S. 54 — ““client matching” does not complete unless the service-side has discovered both client entities (DataReader and DataWriter). While “client matching” is still in progress, service-side does not process requests from the client.”

Repo: crates/rpc/src/discovery_ext.rs::client_matching_complete; crates/rpc/src/replier.rs::Replier::take_enhanced_requests; crates/zerodds-c-api/src/rpc_discovery_ffi.rs (zerodds_rpc_client_matching_complete); C++: runtime/cpp/include/dds/rpc.hpp

Tests: crates/rpc/src/discovery_ext.rs::tests::the_service_unmasks_a_client_once_both_its_endpoints_are_discovered, crates/rpc/src/discovery_ext.rs::tests::an_unannounced_client_is_unmasked_only_when_accepted, crates/rpc/src/replier.rs::tests::an_enhanced_request_of_an_undiscovered_client_is_held, crates/zerodds-c-api/tests/rpc_discovery.rs::the_extension_is_announced_read_and_decides_the_matching

Status: done — Rust (e305669e2c42) und C++ (17a3aef74360): „Client Matching“ ist vollständig, wenn der Reply-Writer den Reply-Reader entdeckt hat, den der Request-Writer des Clients in related_datareader_key nennt, und dieser Reader den Request-Writer nennt (Figure 7.3). Bis dahin bearbeitet der Service keinen Request des Clients. Ein Client ohne Ankündigung wird nur mit accept_unannounced freigegeben. crates/java-omgdds schreibt und liest die PIDs 0x0080 bis 0x0082 (rtps/RpcDiscovery.java, DiscoveryData.buildEndpoint und parseEndpoint, Grenze string<256>: eine Ankündigung darüber wird abgewiesen wie im Decoder von crates/rtps; f65fb3965b5e). ZeroDdsParticipant kündigt service_instance_name an den Endpunkten des Dienstes und related_*_key an beiden Seiten an (9993349aff89). Tests: crates/java-omgdds/java/src/test/java/org/zerodds/rtps/RpcDiscoveryTest.java (theThreeParametersTravelWithTheEndpoint, aStringBeyondTheBoundIsRefused, aTopicCorrespondsByNameOrByAlias). Die Java-Laufzeit hält die Matching-Regel aus den angekündigten Endpunkten ein (1fddccd2b87b): ReplierImpl hält die Requests eines Clients zurück, dessen Reply-Reader der Reply-Writer nicht kennt (Figure 7.3, je Client); RequesterImpl sendet, wenn der Request-Reader der Instanz einen Reply-Writer nennt, den der Reply-Reader entdeckt hat (Figure 7.4). Ein Endpunkt ohne Ankündigung und eine Bindung ohne Discovery-Daten behalten das Matching nach dem Topic. Test: crates/rpc/tests/java/RpcRuntimeRoundtrip.java::overTheJavaPsm über crates/rpc/tests/java_rpc_runtime.rs::the_java_rpc_runtime_and_the_generated_services_run_together (braucht ein JDK; auf dem Mac und dem Linux-Testhost nicht gelaufen).

§7.6.2.2.1 Client Matching: local_mask und Freigabe des Client-Writers

Spec: §7.6.2.2.1, S. 54 und Figure 7.3 — “At the beginning, the service-side DataReader is enabled with local_mask=All_DW so that it does not process any incoming requests. When the service-side DataWriter completes the discovery of a client DataReader, the service DataReader is ready to accept requests from that specific client. Therefore, it unmasks the related client DataWriter.”

Repo: crates/rpc/src/replier.rs::Replier::take_enhanced_requests (Haltelisten je Request-Writer des Clients, GUID aus der Identität des Requests); C++: runtime/cpp/include/dds/rpc.hpp (DataReader::client_matching_complete je Client)

Tests: crates/rpc/src/replier.rs::tests::an_enhanced_request_of_an_undiscovered_client_is_held, crates/rpc/src/replier.rs::tests::the_named_alternatives_release_a_request_of_an_undiscovered_client, crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together, crates/java-omgdds/java/src/test/java/org/omg/dds/rpc/ReplierClientMatchingTest.java, crates/rpc-rust-e2e/tests/replier_activate_client_matching.rs::an_activated_replier_answers_a_held_request_once_its_client_is_matched

Status: done — Rust (e305669e2c42) und C++ (4b6b049312ff, 17a3aef74360) maskieren je Client: ein Request wird erst bearbeitet, wenn client_matching_complete für den Request-Writer dieses Clients gilt; andere Clients werden dadurch nicht aufgehalten. Rust setzt keine local_mask am DataReader der DDS-Schicht; der Replier nimmt die Samples und hält sie in einer eigenen Liste. crates/java-omgdds schreibt und liest die PIDs 0x0080 bis 0x0082 (rtps/RpcDiscovery.java, DiscoveryData.buildEndpoint und parseEndpoint, Grenze string<256>: eine Ankündigung darüber wird abgewiesen wie im Decoder von crates/rtps; f65fb3965b5e). ZeroDdsParticipant kündigt service_instance_name an den Endpunkten des Dienstes und related_*_key an beiden Seiten an (9993349aff89). Tests: crates/java-omgdds/java/src/test/java/org/zerodds/rtps/RpcDiscoveryTest.java (theThreeParametersTravelWithTheEndpoint, aStringBeyondTheBoundIsRefused, aTopicCorrespondsByNameOrByAlias). Die Java-Laufzeit hält die Matching-Regel aus den angekündigten Endpunkten ein (1fddccd2b87b): ReplierImpl hält die Requests eines Clients zurück, dessen Reply-Reader der Reply-Writer nicht kennt (Figure 7.3, je Client); RequesterImpl sendet, wenn der Request-Reader der Instanz einen Reply-Writer nennt, den der Reply-Reader entdeckt hat (Figure 7.4). Ein Endpunkt ohne Ankündigung und eine Bindung ohne Discovery-Daten behalten das Matching nach dem Topic. Test: crates/rpc/tests/java/RpcRuntimeRoundtrip.java::overTheJavaPsm über crates/rpc/tests/java_rpc_runtime.rs::the_java_rpc_runtime_and_the_generated_services_run_together (braucht ein JDK; auf dem Linux-Testhost grün, 3 Tests, d67a980f80b). Die Freigabe hing an einem neuen Sample: ein Replier, dessen Listener bei Ankunft läuft (§7.9.2.2 Weg 1), behielt einen gehaltenen Request, wenn sein Client danach durch Discovery vollständig wurde, ohne dass ein weiteres Sample kam (gemessen mit crates/rpc-rust-e2e/tests/java_peer.rs, Rust-Client von Base2 gegen den Java-Dienst von Derived2 unter Last: „held … replyMatched=0“, danach der Match des Reply-Writers und keine Antwort). Seit 8ae48aed9a0 prüft ein solcher Replier alle 5 ms, solange Requests gehalten sind, ob einer ihrer Clients vollständig ist, und gibt dann frei; ein abgefragter Replier (receiveRequests, waitForRequests, Server) prüft bei jeder Abfrage. Test: ReplierClientMatchingTest.java (rot auf 3f90296146e). Dieselbe Lücke hatte Replier::activate (und activate_async) in Rust, das nur auf DATA_AVAILABLE hörte; seit 30bcfe5cc2f sieht ein Thread des Repliers die gehaltenen Requests alle 5 ms an, solange welche gehalten sind. Test: replier_activate_client_matching.rs (der Reply-Reader des Clients tritt erst nach dem Request in die Partition des Reply-Writers; ohne den Fix gehalten 1, beantwortet 0).

§7.6.2.2.2 Service Matching am Client: keine Requests bis zum Abschluss

Spec: §7.6.2.2.2, S. 55 — ““service matching” does not complete unless the client-side has discovered both service DDS Entities (DataReader and DataWriter) and it does not send requests to the service until “service matching” completes.”

Repo: crates/rpc/src/discovery_ext.rs::service_matching_complete; crates/rpc/src/requester.rs::Requester::service_matched; crates/zerodds-c-api/src/rpc_discovery_ffi.rs (zerodds_rpc_service_matching_complete); C++: runtime/cpp/include/dds/rpc.hpp

Tests: crates/rpc/src/discovery_ext.rs::tests::the_client_waits_for_both_service_endpoints, crates/rpc/src/discovery_ext.rs::tests::the_two_endpoints_must_name_each_other, crates/rpc/src/discovery_ext.rs::tests::the_client_addresses_the_instance_it_names, crates/rpc/src/discovery_ext.rs::tests::an_unannounced_service_completes_only_when_accepted, crates/rpc-rust-e2e/tests/enhanced_e2e.rs::the_client_waits_for_the_service_instance_it_names, crates/zerodds-c-api/tests/rpc_discovery.rs::the_extension_is_announced_read_and_decides_the_matching

Status: done — Rust (e305669e2c42) und C++ (17a3aef74360): „Service Matching“ ist vollständig, wenn Request-Reader und Reply-Writer des Services entdeckt sind, einander nennen und der Request-Reader den instance_name des Clients ankündigt (Figure 7.4); der Client sendet vorher nicht. Ein Service ohne Ankündigung wird nur mit accept_unannounced als vollständig gelesen. crates/java-omgdds schreibt und liest die PIDs 0x0080 bis 0x0082 (rtps/RpcDiscovery.java, DiscoveryData.buildEndpoint und parseEndpoint, Grenze string<256>: eine Ankündigung darüber wird abgewiesen wie im Decoder von crates/rtps; f65fb3965b5e). ZeroDdsParticipant kündigt service_instance_name an den Endpunkten des Dienstes und related_*_key an beiden Seiten an (9993349aff89). Tests: crates/java-omgdds/java/src/test/java/org/zerodds/rtps/RpcDiscoveryTest.java (theThreeParametersTravelWithTheEndpoint, aStringBeyondTheBoundIsRefused, aTopicCorrespondsByNameOrByAlias). Die Java-Laufzeit hält die Matching-Regel aus den angekündigten Endpunkten ein (1fddccd2b87b): ReplierImpl hält die Requests eines Clients zurück, dessen Reply-Reader der Reply-Writer nicht kennt (Figure 7.3, je Client); RequesterImpl sendet, wenn der Request-Reader der Instanz einen Reply-Writer nennt, den der Reply-Reader entdeckt hat (Figure 7.4). Ein Endpunkt ohne Ankündigung und eine Bindung ohne Discovery-Daten behalten das Matching nach dem Topic. Test: crates/rpc/tests/java/RpcRuntimeRoundtrip.java::overTheJavaPsm über crates/rpc/tests/java_rpc_runtime.rs::the_java_rpc_runtime_and_the_generated_services_run_together (braucht ein JDK; auf dem Mac und dem Linux-Testhost nicht gelaufen).

§7.6.2.2.2 Service Matching: local_mask, Warteschlange, Freigabe

Spec: §7.6.2.2.2, S. 55 und Figure 7.4 — “At the beginning, the client-side DataWriter is enabled local_mask=All_DR such that it does not send any request at all. Attempts to send requests would be queued. When the client-side DataReader completes the discovery of a service DataWriter, the client DataWriter updates the local mask so that it can send requests to the service DataReader as long as it has been discovered.”

Repo: crates/rpc/src/requester.rs::Requester::wait_for_service (Rust: der sendende Aufruf hält den Request); C++: runtime/cpp/include/dds/rpc.hpp (Requester::queued_requests); Java: runtime/java/src/main/java/org/zerodds/ddsrpc/RequesterImpl.java (Warteschlange queue, flushQueue)

Tests: crates/rpc/src/requester.rs::tests::an_enhanced_request_waits_for_the_service_and_fails_without_sending, crates/rpc/src/requester.rs::tests::the_fail_setting_does_not_wait, crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together, crates/rpc/tests/java_rpc_runtime.rs::the_java_rpc_runtime_and_the_generated_services_run_together

Status: done — Rust (e305669e2c42): Der Client sendet nicht; der Aufruf hält den Request bis höchstens request_timeout und schlägt dann mit RpcError::ServiceNotMatched fehl, der Request steht danach nicht in einer Warteschlange. C++ (4b6b049312ff, 17a3aef74360) stellt Requests in eine Warteschlange und gibt sie frei, sobald service_matching_complete gilt; eine Maske local_mask = All_DR gibt es in keiner Laufzeit, die Freigabe ersetzt sie. crates/java-omgdds schreibt und liest die PIDs 0x0080 bis 0x0082 (rtps/RpcDiscovery.java, DiscoveryData.buildEndpoint und parseEndpoint, Grenze string<256>: eine Ankündigung darüber wird abgewiesen wie im Decoder von crates/rtps; f65fb3965b5e). ZeroDdsParticipant kündigt service_instance_name an den Endpunkten des Dienstes und related_*_key an beiden Seiten an (9993349aff89). Tests: crates/java-omgdds/java/src/test/java/org/zerodds/rtps/RpcDiscoveryTest.java (theThreeParametersTravelWithTheEndpoint, aStringBeyondTheBoundIsRefused, aTopicCorrespondsByNameOrByAlias). Die Java-Laufzeit hält die Matching-Regel aus den angekündigten Endpunkten ein (1fddccd2b87b): ReplierImpl hält die Requests eines Clients zurück, dessen Reply-Reader der Reply-Writer nicht kennt (Figure 7.3, je Client); RequesterImpl sendet, wenn der Request-Reader der Instanz einen Reply-Writer nennt, den der Reply-Reader entdeckt hat (Figure 7.4). Ein Endpunkt ohne Ankündigung und eine Bindung ohne Discovery-Daten behalten das Matching nach dem Topic. Test: crates/rpc/tests/java/RpcRuntimeRoundtrip.java::overTheJavaPsm über crates/rpc/tests/java_rpc_runtime.rs::the_java_rpc_runtime_and_the_generated_services_run_together (braucht ein JDK; auf dem Mac und dem Linux-Testhost nicht gelaufen).

§7.7 Interface Evolution

§7.7.1 Evolution in der Basic-Abbildung

Spec: §7.7.1, S. 56 — “The Basic Service Profile has limited support for interface evolution […] Interface evolution is constrained by the rules described herein.”

Repo: —

Tests: —

Status: n/a (informative) — Einleitung.

§7.7.1.1 Client mit weniger Operationen

Spec: §7.7.1.1, S. 56 — “If a client uses an interface that has fewer methods than that of the service, it is simply oblivious of the fact that the service has more capabilities than the client can use.”

Repo: crates/rpc/src/codegen.rs::build_call_union (Labels aus dem Namen der Operation, nicht aus der Position); crates/rpc/src/function_call.rs (dispatch_request nach Opcode)

Tests: crates/rpc/src/codegen.rs::tests::the_case_labels_are_the_operation_hashes, crates/rpc/tests/profile_conformance.rs::function_call_processing_dispatches_to_correct_operation, crates/rpc-rust-e2e/tests/evolution_styles_discovery.rs::versions::an_old_client_calls_a_new_service

Status: done — das Label einer Operation ist der HASH ihres Namens (64d55a6c8f94, c4a68d078000) und hängt nicht von den anderen Operationen des Interface ab; der Service ruft nach Label auf. Für Enhanced läuft ein Client der alten Fassung gegen den Service der neuen Fassung (Test 3, 414e077c527d); für Basic gibt es drei erzeugte Fassungen (basic_old, basic_new, basic_fewer in crates/rpc-rust-e2e/build.rs, b21c700bc86e) und die Tests evolution_styles_discovery.rs::basic_versions::a_client_with_fewer_operations_calls_a_service_with_more, an_old_basic_client_calls_a_new_service und a_new_basic_client_calls_an_old_service.

§7.7.1.1 Client mit mehr Operationen: REMOTE_EX_UNSUPPORTED

Spec: §7.7.1.1, S. 56 — “If the client uses an interface with more operations than that of the service, invocation of an unsupported operation shall result in REMOTE_EX_UNSUPPORTED remote exception code.”

Repo: crates/lang-rules/src/emit/interface_rust.rs (Dispatcher, Fall unbekannte Operation: RemoteExceptionCode::Unsupported); crates/lang-rules/src/emit/interface_java/calls.rs; crates/lang-rules/src/emit/interface_cpp/calls.rs (Methode answer, Fall default)

Tests: crates/rpc-rust-e2e/tests/e2e.rs::the_generated_calculator_binding_runs_every_call (erwartet Unsupported), crates/rpc/tests/java_rpc_runtime.rs::the_generated_function_call_client_calls_the_generated_service (FunctionCallRoundtrip.java, erwartet RemoteUnsupportedError), crates/rpc/tests/cpp_function_call.rs::the_generated_client_calls_the_generated_service (function_call_roundtrip.cpp, erwartet RemoteUnsupportedError)

Status: done — der erzeugte Rust-Dispatcher (b527a9f58028), der erzeugte Java-Dienst (c512ee365514) und der erzeugte C++-Dienst der Basic-Abbildung (62ccb5f757a3) antworten auf eine unbekannte Operation mit REMOTE_EX_UNSUPPORTED; der C++-Client wirft RemoteUnsupportedError. Die Spec hat hier zwei Aussagen (§7.7.1.1: REMOTE_EX_UNSUPPORTED; Tabelle in §7.5.2: REMOTE_EX_UNKNOWN_OPERATION für „The operation called is unknown“); die Abbildung folgt §7.7.1.1. Der Enhanced-Dispatcher antwortet mit REMOTE_EX_UNKNOWN_OPERATION (§7.7.2.1; enhanced_function_call_roundtrip.cpp).

§7.7.1.2 Reihenfolge von Operationen und Basen ohne Wirkung

Spec: §7.7.1.2, S. 56 — “Reordering operations has no impact on the semantics of the interface because every interface has set semantics. […] Reordering base interfaces has no impact on the semantics of the interface.”

Repo: crates/rpc/src/codegen.rs::build_call_union (Labels aus dem Namen, nicht aus der Position); crates/rpc/src/evolution_rules.rs::is_compatible

Tests: crates/rpc/src/codegen.rs::tests::the_case_labels_are_the_operation_hashes, crates/rpc/src/evolution_rules.rs::tests::basic_mapping_reorder_operations_is_compatible

Status: done — das Label einer Operation ist der HASH ihres Namens (64d55a6c8f94); Reihenfolge von Operationen und Basen ändert kein Label. Die Tabelle evolution_rules nennt das Umordnen in Basic kompatibel (17fe2de3f32e).

§7.7.1.3 Keine Änderung der Signatur in der Basic-Abbildung

Spec: §7.7.1.3, S. 56 — “The Basic Service Profile shall not support any modifications to the operation signatures including exception specification.”

Repo: crates/rpc/src/evolution_rules.rs::is_compatible (Basic: ChangeSignature und die Enhanced-Änderungen inkompatibel)

Tests: crates/rpc/src/evolution_rules.rs::tests::basic_mapping_change_signature_is_breaking

Status: done — in der Basic-Abbildung gibt es keine Änderung der Signatur, die als kompatibel geführt wird (17fe2de3f32e); die Basic-Typen sind @final und tragen keine Member-IDs.

§7.7.2 Evolution in der Enhanced-Abbildung

Spec: §7.7.2, S. 56 — “The Enhanced Service Profile supports flexible interface evolution. […] The interface mapping rules in the previous sub clause are designed such that the assignability rules defined in [DDS-XTypes] will ensure seamless evolution from Iold to Inew.”

Repo: —

Tests: —

Status: n/a (informative) — Einleitung und Begriffe; die Regeln folgen als Items.

§7.7.2.1 Neue Operation

Spec: §7.7.2.1, S. 56–57 — “Cold can invoke Snew because the additional member in Requestnew is never populated by Cold. […] When Cnew invokes Sold, Sold receives a sample with no active member […] In such cases, the service (Sold) returns Replyold with remoteEx = REMOTE_EX_UNKNOWN_OPERATION.”

Repo: crates/lang-rules/src/emit/interface_rust/enhanced.rs (choice_codec: eine unbekannte Member-ID wird UnknownOp; answer_unknown_operations); C++: crates/lang-rules/src/emit/interface_cpp/enhanced_codec.rs, crates/lang-rules/src/emit/interface_cpp/calls.rs; Java: crates/lang-rules/src/emit/interface_java/enhanced_calls.rs

Tests: crates/rpc-rust-e2e/tests/enhanced_generated.rs::a_member_the_interface_does_not_have_is_unknown_operation, crates/rpc-rust-e2e/tests/enhanced_generated.rs::an_unknown_member_is_answered_unknown_operation, crates/rpc-rust-e2e/tests/enhanced_generated.rs::a_reply_carries_remote_ex, crates/rpc/tests/cpp_enhanced_function_call.rs::the_generated_enhanced_client_calls_the_generated_enhanced_service, crates/rpc/tests/java_enhanced_codec.rs::the_generated_java_codec_writes_the_octets_of_the_clause

Status: done — die Member-IDs sind der HASH des Namens; ein Member, den die Fassung des Services nicht kennt, lässt die Request-Choice ohne aktives Member (Rust UnknownOp) und der Service antwortet mit remoteEx = REMOTE_EX_UNKNOWN_OPERATION (Rust 41b3b02f7a20, C++ 45ead22cc2b9, Java 2ea77f7dad8a). Ein alter Client erreicht einen neuen Service, weil er das zusätzliche Member nie setzt. Rust und C++ führen den Fall aus; für Java prüfen die Tests den Codec und den erzeugten Text (enhanced_java_calls.rs).

§7.7.2.2 Entfernte Operation

Spec: §7.7.2.2, S. 57 — “When Cold calls Snew, Cold receives REMOTE_EX_UNKNOWN_OPERATION RemoteExceptionCode.”

Repo: wie bei „§7.7.2.1 Neue Operation“; der Client liest remoteEx als RpcError::RemoteException (crates/rpc/src/enhanced.rs)

Tests: crates/rpc-rust-e2e/tests/enhanced_generated.rs::an_unknown_member_is_answered_unknown_operation, crates/rpc-rust-e2e/tests/enhanced_e2e.rs::an_enhanced_remote_exception_is_the_remote_ex_member, crates/rpc/src/enhanced.rs::tests::a_remote_ex_reply_round_trips_every_code

Status: done — ruft ein Client eine Operation auf, die der neue Service nicht mehr hat, erhält er REMOTE_EX_UNKNOWN_OPERATION (41b3b02f7a20, e305669e2c42). Ein neuer Client mit einer Teilmenge der Operationen des alten Services ist der Fall von §7.7.1.1 „weniger Operationen“, hier ohne Fehler.

§7.7.2.3 Reihenfolge von Operationen und Basen

Spec: §7.7.2.3, S. 57 — “Due to the use of md5 hash algorithm to compute the member ids, this specification considers two interfaces equivalent as long as they contain the same operations.”

Repo: crates/rpc/src/codegen.rs::build_enhanced_service (@Autoid: Member-ID = HASH des Namens, 28 Bit); crates/rpc/src/evolution_rules.rs::is_compatible

Tests: crates/rpc/src/codegen.rs::tests::enhanced_autoid_member_ids_are_the_hash_of_the_name, crates/rpc/src/codegen.rs::tests::enhanced_inheritance_is_flattened, crates/rpc/src/evolution_rules.rs::tests::enhanced_mapping_reorder_operations_is_compatible

Status: done — die Member-ID einer Operation ist der HASH ihres Namens, nicht ihre Position (0edbbcf11324); zwei Interfaces mit denselben Operationen haben dieselben IDs, gleich in welcher Reihenfolge Operationen und Basen stehen.

§7.7.2.4 Duck Typing

Spec: §7.7.2.4, S. 57 — “Enhanced Service Profile supports “duck typing” evolution of an interface.”

Repo: crates/rpc/src/codegen.rs::build_enhanced_service (Vererbung flach, Typnamen der Basis); crates/lang-rules/src/emit/interface_rust/enhanced.rs (abgeleiteter Dispatcher bedient geerbte Operationen)

Tests: crates/rpc/src/codegen.rs::tests::enhanced_inheritance_is_flattened, crates/rpc-rust-e2e/tests/enhanced_generated.rs::a_derived_request_has_the_inherited_operation, crates/rpc-rust-e2e/tests/enhanced_generated.rs::a_derived_dispatcher_serves_an_inherited_member

Status: done — die Request-Choice eines abgeleiteten Interface enthält die geerbten Operationen mit denselben Member-IDs, die sie im Interface selbst hätten (0edbbcf11324, 7607e8680852); die Topic-Namen kommen aus dem Namen des Interface. Ein Interface mit geerbten und eines mit direkt definierten Operationen gleichen Namens sind auf der Leitung gleich.

§7.7.2.5.1 Parameter hinzufügen oder entfernen

Spec: §7.7.2.5.1, S. 57 — “Adding and removing parameters in an operation shall break compatibility with the older interface. The @final annotation on the In and Out structures enforce this restriction. It is, however, possible to mark an operation @mutable to allow the In and Out structures to be mutable”.

Repo: crates/rpc/src/codegen.rs::build_enhanced_service (In, Out, Result sind @final, bei @Mutable an der Operation @mutable); crates/lang-rules/src/emit/interface_rust/enhanced.rs; die Codecs für C++ und Java

Tests: crates/rpc-rust-e2e/tests/enhanced_generated.rs::a_mutable_operation_has_mutable_structures, crates/rpc-rust-e2e/tests/enhanced_generated.rs::a_mutable_structure_skips_a_member_it_does_not_know, crates/rpc-rust-e2e/tests/enhanced_generated.rs::an_absent_member_of_a_mutable_structure_takes_its_default, crates/rpc/src/codegen.rs::tests::enhanced_mutable_operation_has_mutable_structures, crates/rpc/src/evolution_rules.rs::tests::enhanced_mapping_add_remove_param_is_breaking; C++: crates/rpc/tests/cpp_enhanced_function_call.rs::the_generated_enhanced_client_calls_the_generated_enhanced_service; Java: crates/rpc/tests/java_enhanced_codec.rs::the_generated_java_codec_writes_the_octets_of_the_clause

Status: done — ohne @Mutable sind die Strukturen @final und tragen keine Member-Header (ein weiterer Parameter bricht die Kompatibilität); mit @Mutable trägt jeder Parameter einen EMHEADER mit der ID des Namens, ein unbekannter Member wird übersprungen und ein fehlender nimmt seinen Default (41b3b02f7a20, 77ded59f712c). Die Tabelle evolution_rules nennt das Hinzufügen und Entfernen von Parametern inkompatibel (17fe2de3f32e).

§7.7.2.5.2 Parameter umordnen

Spec: §7.7.2.5.2, S. 57 — “Reordering parameters in an operation shall break compatibility with the older interface. […] It is, however, possible to mark an operation @mutable to allow reordering of parameters. In that case the synthesized structures (In and Out) shall be annotated @mutable.”

Repo: crates/rpc/src/codegen.rs::build_enhanced_service (Member-IDs aus dem Parameternamen; @final ohne @Mutable)

Tests: crates/rpc-rust-e2e/tests/enhanced_generated.rs::a_mutable_operation_has_mutable_structures, crates/rpc/src/evolution_rules.rs::tests::enhanced_mapping_reorder_params_is_breaking, crates/rpc-rust-e2e/tests/evolution_styles_discovery.rs::versions::an_old_client_calls_a_new_service, crates/rpc-rust-e2e/tests/evolution_styles_discovery.rs::versions::a_new_client_calls_an_old_service

Status: done — ohne @Mutable stehen die Parameter ohne Header in der Reihenfolge der Deklaration (Test 1, Fall Calc_add_In), ein Umordnen bricht die Kompatibilität; mit @Mutable hat jeder Parameter eine ID aus seinem Namen (41b3b02f7a20). Zwei erzeugte Fassungen von interface Svc haben @Mutable void mix(in long x, in long y) und @Mutable void mix(in long y, in long x); Client und Service der jeweils anderen Fassung tauschen die Argumente unter ihren Namen aus. Rust: Tests 3 und 4 (414e077c527d). C++: crates/rpc/tests/cpp/enhanced_evolution_roundtrip.cpp über crates/rpc/tests/cpp_enhanced_function_call.rs::two_generated_cpp_versions_of_an_interface_run_against_each_other (49525d7e5e80, auf dem Linux-Testhost gelaufen). Java: crates/rpc/tests/java/EvolutionChecks.java über crates/rpc/tests/java_enhanced_codec.rs::two_generated_java_versions_of_an_interface_run_against_each_other (19add727524b, braucht ein JDK).

§7.7.2.5.3 Typ eines Parameters ändern

Spec: §7.7.2.5.3, S. 57 — “Changing the type of the parameters is allowed by this specification. The type assignability rules shall be as described in [DDS-XTypes].”

Repo: —

Tests: crates/rpc-rust-e2e/tests/java_peer.rs::a_java_client_calls_a_rust_service, crates/rpc-rust-e2e/tests/java_peer.rs::a_rust_client_calls_a_java_service, crates/rpc-rust-e2e/tests/java_peer.rs::versions::a_changed_parameter_type_does_not_match_the_java_client, crates/rpc-rust-e2e/tests/java_peer.rs::versions::an_old_java_client_calls_an_old_rust_service, crates/rpc-rust-e2e/tests/java_peer.rs::appended_member::a_member_appended_to_a_mutable_structure_matches_the_java_client

Status: done — Rust und C++ sind umgesetzt: die Topics tragen die TypeInformation, die Paarung folgt der Zuweisbarkeit nach XTypes. Tests (Linux-Testhost, grün): crates/rpc-rust-e2e/tests/enhanced_type_information.rs::appended_member::a_member_appended_to_a_parameter_type_is_matched (ein an eine @mutable-Struktur angehängtes Member), ...::versions::a_changed_parameter_type_does_not_match (long zu string: ServiceNotMatched; mit Zuordnung nach Typname würde der Request gesendet und vom Dienst abgewiesen, mit einem Kontrolllauf gemessen); für C++ cpp_rpc_real_library.rs::the_cpp_binding_runs_against_libzerodds (ev_changed: der Client findet den Dienst nicht). Java (2d0f809c6e2, 9b1608508c5, d67a980f80b), gegen Rust-Peers über RTPS: crates/rpc-rust-e2e/tests/java_peer.rs::versions::a_changed_parameter_type_does_not_match_the_java_client (long zu string: der Java-Client findet den Dienst nicht, der Rust-Dienst sieht keinen Request; auf 78f243b596f, vor der Paarung nach Zuweisbarkeit, paarte der Java-Client nach dem Typnamen, rief den Dienst und bekam keine Antwort), Kontrolle ...::versions::an_old_java_client_calls_an_old_rust_service, und ...::appended_member::a_member_appended_to_a_mutable_structure_matches_the_java_client (ein an Pose angehängtes Member: Match, das Argument erreicht den Dienst). Die Tabelle evolution_rules nennt die Änderung kompatibel (enhanced_mapping_change_param_type_is_compatible).

§7.7.2.5.4 Rückgabetyp hinzufügen oder entfernen

Spec: §7.7.2.5.4, S. 57 — “Adding and removing return type shall break compatibility with the older interface. […] It is, however, possible to annotate an operation @Mutable to allow the In and Out structures to be mutable and consequently support addition or removal of return type”.

Repo: crates/rpc/src/codegen.rs::build_enhanced_service (der Rückgabewert ist das Member return der Out-Struktur; @final, mit @Mutable @mutable)

Tests: crates/rpc/src/codegen.rs::tests::enhanced_out_carries_the_return_value, crates/rpc/src/codegen.rs::tests::enhanced_mutable_operation_has_mutable_structures, crates/rpc-rust-e2e/tests/enhanced_generated.rs::an_absent_member_of_a_mutable_structure_takes_its_default, crates/rpc/src/evolution_rules.rs::tests::enhanced_mapping_add_remove_return_type_is_breaking

Status: done — der Rückgabewert ist ein Member der Out-Struktur; ohne @Mutable ist sie @final (Hinzufügen oder Entfernen bricht die Kompatibilität), mit @Mutable ist sie @mutable und wird wie die In-Struktur gelesen (41b3b02f7a20, 77ded59f712c). Die Tests zur Dekodierung eines fehlenden und eines unbekannten Members laufen an der In-Struktur; der Codec der Out-Struktur wird vom selben Generator erzeugt.

§7.7.2.5.5 Rückgabetyp ändern

Spec: §7.7.2.5.5, S. 58 — “Changing the type of the return value is allowed by this specification. The type assignability rules shall be as described in [DDS-Xtypes].”

Repo: —

Tests: crates/rpc/tests/cpp_rpc_real_library.rs::the_cpp_binding_runs_against_libzerodds, crates/rpc-rust-e2e/tests/java_peer.rs::a_java_client_calls_a_rust_service, crates/rpc-rust-e2e/tests/java_peer.rs::a_rust_client_calls_a_java_service, crates/rpc-rust-e2e/tests/java_peer.rs::versions::a_return_type_the_old_one_is_not_assignable_to_does_not_match_the_java_client, crates/rpc-rust-e2e/tests/java_peer.rs::appended_member::a_member_appended_to_a_mutable_structure_matches_the_java_client

Status: done — Rust ist umgesetzt wie bei „§7.7.2.5.3 Typ eines Parameters ändern“. Tests (Linux-Testhost, grün): crates/rpc-rust-e2e/tests/enhanced_type_information.rs::return_type::a_return_type_the_old_one_is_not_assignable_to_does_not_match (long zu long long: ServiceNotMatched) und ...::appended_member::a_return_type_with_an_appended_member_is_matched (ein an eine @mutable-Struktur im Rückgabetyp angehängtes Member: der alte Client liest die Antwort des neuen Dienstes, f447919ebed2). C++ trägt dieselbe TypeInformation (Item zu §7.5.1.2.6); cpp_rpc_real_library.rs::the_cpp_binding_runs_against_libzerodds prüft einen Rückgabetyp mit angehängtem Member (der alte Client liest die Antwort) und einen von long auf long long erweiterten (kein Match) (a7f9353650e). Java (2d0f809c6e2, d67a980f80b), gegen Rust-Peers über RTPS: crates/rpc-rust-e2e/tests/java_peer.rs::versions::a_return_type_the_old_one_is_not_assignable_to_does_not_match_the_java_client (long zu long long: der Reply-Reader des Java-Clients paart nicht mit dem Writer des Dienstes; auf 78f243b596f paarte er nach dem Typnamen, und der Aufruf von add kam durch) und ...::appended_member::a_member_appended_to_a_mutable_structure_matches_the_java_client (Rückgabetyp Pose mit angehängtem Member: der Java-Client liest origin.x=3). Die Tabelle evolution_rules nennt die Änderung kompatibel (enhanced_mapping_change_return_type_is_compatible).

§7.7.2.5.6 Exception hinzufügen oder entfernen

Spec: §7.7.2.5.6, S. 58 — “This specification supports adding and removing one or more exceptions on an operation. The @mutable annotation on the return structure will support this interface evolution.”

Repo: crates/rpc/src/codegen.rs::build_enhanced_service (Result ist eine Choice über result und <name>_ex, Member-IDs aus dem Namen); crates/lang-rules/src/emit/interface_rust/enhanced.rs (choice_codec der Result ohne UnknownOp); C++: crates/lang-rules/src/emit/interface_cpp/calls.rs; Java: crates/lang-rules/src/emit/interface_java/enhanced_calls.rs

Tests: crates/rpc/src/codegen.rs::tests::enhanced_result_carries_out_and_the_exceptions, crates/rpc-rust-e2e/tests/enhanced_generated.rs::a_result_is_a_choice_of_the_result_and_the_exceptions, crates/rpc/src/evolution_rules.rs::tests::enhanced_mapping_add_remove_exception_is_compatible, crates/rpc-rust-e2e/tests/enhanced_generated.rs::an_unknown_exception_member_of_a_result_decodes_as_unknown_ex, crates/rpc-rust-e2e/tests/enhanced_generated.rs::the_generated_client_reports_unknown_exception_for_an_unknown_result_member, crates/rpc-rust-e2e/tests/enhanced_generated.rs::an_exception_the_operation_does_not_declare_is_unknown_exception, crates/rpc/tests/java_enhanced_codec.rs::the_generated_java_service_and_client_answer_the_error_cases_of_the_clauses

Status: done — jede Exception ist ein eigenes Member <name>_ex der Result-Choice mit ID aus dem Namen (41b3b02f7a20); das Hinzufügen oder Entfernen einer Exception ändert die IDs der übrigen nicht. Der erzeugte Rust-Client meldet ein unbekanntes _ex-Member der Result als RpcError::RemoteException mit REMOTE_EX_UNKNOWN_EXCEPTION, eine nicht deklarierte Exception des Service ebenso (f88947810821). Java: EnhancedRuntimeChecks.java (82ec363b6b82) und EvolutionChecks.java (19add727524b). C++: enhanced_function_call_roundtrip.cpp prüft eine nicht deklarierte Exception der Implementierung und eine Result mit unbekanntem Member (der Client wirft RemoteUnknownExceptionError), enhanced_evolution_roundtrip.cpp die Fassung mit zusätzlicher Exception gegen die ohne sie (49525d7e5e80, auf dem Linux-Testhost gelaufen).

§7.7.2.5.6 REMOTE_EX_UNKNOWN_EXCEPTION für eine unbekannte Exception

Spec: §7.7.2.5.6, S. 58 — “The language binding that provides function call/return semantics may throw REMOTE_EX_UNKNOWN_EXCEPTION if the RPC call results into an exception that client does not understand.”

Repo: —

Tests: —

Status: n/a (informative) — Erlaubnis.

§7.7 — Tabelle der Evolution

Spec: §7.7.1.1 bis §7.7.2.5.6, S. 56–58 — wie die Items oben.

Repo: crates/rpc/src/evolution_rules.rs::is_compatible und compatible_evolutions

Tests: crates/rpc/src/evolution_rules.rs::tests::basic_mapping_add_remove_operation_is_compatible, crates/rpc/src/evolution_rules.rs::tests::basic_mapping_has_four_compatible_evolutions, crates/rpc/src/evolution_rules.rs::tests::enhanced_compatible_evolutions_includes_8_of_12, crates/rpc/src/evolution_rules.rs::tests::a_mutable_operation_allows_parameter_changes, crates/rpc/src/evolution_rules.rs::tests::mutable_changes_nothing_that_was_compatible_or_never_was, crates/rpc/src/evolution_rules.rs::tests::a_mutable_operation_has_eleven_compatible_enhanced_evolutions

Status: done — die Tabelle stimmt mit §7.7.1.1 bis §7.7.2.5.6 überein (17fe2de3f32e): Basic nennt das Hinzufügen, Entfernen und Umordnen von Operationen kompatibel, jede Änderung der Signatur inkompatibel; Enhanced nennt Typänderungen und das Hinzufügen oder Entfernen von Exceptions kompatibel und das Hinzufügen, Entfernen und Umordnen von Parametern und Rückgabetyp inkompatibel. Mit mutable = true in is_compatible und compatible_evolutions nennt sie die drei Änderungen kompatibel, die die Spec mit @mutable erlaubt (§7.7.2.5.1, .2, .4; 943d3afd7cb6). Kein Code außerhalb der Tests ruft die Tabelle auf; die Spec verlangt keine Prüfung zur Laufzeit (aus dem Code gelesen).


§7.8 Request and Reply Correlation

§7.8.1 Basic: Korrelation über RequestHeader und ReplyHeader

Spec: §7.8.1, S. 58 — “The Basic service profile uses the RequestHeader and ReplyHeader described in sub clause 7.5.1.1.1.”

Repo: crates/rpc/src/requester.rs::Requester::tick (related_request_id gegen die offenen Requests); crates/rpc/src/replier.rs::Replier::tick

Tests: crates/rpc/src/requester.rs::tests::tick_correlates_reply_with_pending_slot, crates/rpc/tests/runtime_e2e.rs::e2e_multi_pending_requests_all_get_their_reply, crates/rpc/tests/runtime_e2e.rs::e2e_client_side_request_identity_is_the_one_the_reply_relates_to, crates/rpc-rust-e2e/tests/e2e.rs::a_live_request_identity_is_the_rtps_identity_of_the_request_writer

Status: done — die Rust-Laufzeit ordnet über RequestHeader::request_id und ReplyHeader::related_request_id zu (f06c1eaf3d3a); die request_id ist GUID und Folgenummer des Request-Writers (2314c1c5fb58). C++ und Java siehe das nächste Item.

§7.8.1 C++ und Java: requestId im Header, Zuordnung über relatedRequestId

Spec: §7.8.1, S. 58 — wie oben.

Repo: C++: runtime/cpp/include/dds/rpc.hpp (Requester::send_request trägt die Identität aus DataWriter::next_identity() in RequestHeader::request_id ein, Replier::dispatch_requests antwortet mit header.request_id); Java: runtime/java/src/main/java/org/zerodds/ddsrpc/RequesterImpl.java, ReplierImpl.java

Tests: crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together (die Anbindung im Speicher gibt keine Identität heraus), crates/rpc/tests/java_rpc_runtime.rs::the_java_rpc_runtime_and_the_generated_services_run_together

Status: done — der Header trägt die explizite request_id, der Replier liest sie aus dem Header, nicht aus SampleInfo (58634aa2702a); Requester filtern fremde Replies nach der GUID ihres Request-Writers (35aa702e4900). Die Anbindungen an ZeroDDS in C++ und Java geben die Identität des Samples ebenfalls aus (2bfb2786121b, a2a9a67acb58).

Spec: §7.8.2, S. 58 — “To support propagation of the sample identity of a related request this specification extends the [RTPS] specification adding a new parameter id PID_RELATED_SAMPLE_IDENTITY with value 0x0083. This parameter may appear in the inlineQos sub-message element of the DATA sub-message”.

Repo: crates/rtps/src/parameter_list.rs (pid::RELATED_SAMPLE_IDENTITY); crates/rtps/src/inline_qos.rs (related_sample_identity_param, find_related_sample_identity)

Tests: crates/rtps/src/inline_qos.rs::tests::related_sample_identity_param_uses_pid_0x0083, crates/rtps/src/inline_qos.rs::tests::find_related_sample_identity_finds_pid, crates/rtps/src/parameter_list.rs::tests::rpc_pid_constants_match_spec

Status: done — Parameter-ID 0x0083, Kodierung und Suche in der Inline-QoS (b5224bd70dbb); das Lesen maskiert nur das Must-Understand-Bit, eine herstellereigene ID 0x8083 wird nicht als 0x0083 gelesen (1a30e3dd368a).

Spec: §7.8.2, S. 58 — “The PID_RELATED_SAMPLE_IDENTITY shall be used for data samples sent as reply to a request.”

Repo: crates/dcps/src/publisher.rs::DataWriter::write_related und crates/dcps/src/runtime.rs::DcpsRuntime::write_user_sample_related (schreiben 0x0083 und eProsimas 0x800f); crates/rpc/src/replier.rs (Enhanced-Reply über write_related); C++: zerodds_writer_write_related in crates/zerodds-c-api; Java: runtime/java/src/main/java/org/zerodds/ddsrpc/ZeroDdsParticipant.java (Writer.write(sample, related)); crates/rmw-zerodds-shim/src/services.rs

Tests: crates/rtps/src/inline_qos.rs::tests::reply_inline_qos_contains_only_pid_0x0083, crates/dcps/src/runtime.rs::tests::the_related_identity_is_0x0083_or_eprosimas_0x800f_from_a_writer_that_means_it, crates/rpc-rust-e2e/tests/enhanced_e2e.rs::an_enhanced_call_is_answered_through_the_related_sample_identity, crates/rpc/tests/cpp_rpc_zerodds_related_identity.rs::the_zerodds_binding_sends_and_reads_the_related_sample_identity, crates/java-omgdds/java/src/test/java/org/omg/dds/rpc/ZeroDdsParticipantTest.java::aWriteReturnsItsIdentityAndTheReaderSeesItWithTheRelatedOne

Status: done — in der Enhanced-Abbildung trägt jede Antwort den Parameter 0x0083 mit der Identität des Requests und der Requester ordnet danach zu: Rust (8385434c2326, e305669e2c42), C++ (2bfb2786121b, 5a472acf053e), Java (a2a9a67acb58, der Java-PSM-Writer gibt die Identität zurück und nimmt eine verwandte entgegen). Die Basic-Abbildung korreliert über den Header (§7.8.1). Die ROS-2-Dienste nutzen denselben Schreibpfad.

Spec: §7.8.2, S. 58 — wie oben.

Repo: Rust: crates/rpc/src/replier.rs::Replier::write_reply (Enhanced: DataWriter::write_related), crates/rpc/src/requester.rs::Requester::tick (liest die verwandte Identität aus SampleWire), crates/dcps/src/publisher.rs::DataWriter::write_related, crates/dcps/src/runtime.rs::DcpsRuntime::write_user_sample_related, crates/dcps/src/subscriber.rs::DataReader::take_with_wire, crates/rtps/src/inline_qos.rs::find_related_sample_identity. C++: runtime/cpp/include/dds/rpc/zerodds.hpp (Writer::write_related, Reader::take) über zerodds_writer_write_related und zerodds_reader_take_wire der C-API. Java: runtime/java/src/main/java/org/zerodds/ddsrpc/ZeroDdsParticipant.java (Writer.write(sample, related), Reader.take) über DataWriterImpl.writeIdentified der Java PSM. Commits: 1a30e3dd368a (rtps: 0x8083 wird nicht mehr als 0x0083 gelesen), 8385434c2326 (dcps), 5a472acf053e (c-api), e305669e2c42 (Rust), 2bfb2786121b (C++), a2a9a67acb58 (Java)

Tests: crates/rtps/src/inline_qos.rs::tests::a_vendor_specific_0x8083_is_not_the_related_sample_identity, crates/rtps/src/inline_qos.rs::tests::find_related_sample_identity_with_must_understand_bit_works, crates/dcps/src/subscriber.rs::tests::take_with_wire_hands_over_the_identity_and_the_related_identity, crates/dcps/src/publisher.rs::tests::write_related_without_a_runtime_is_refused, crates/zerodds-c-api/tests/related_sample_identity.rs::a_related_sample_identity_reaches_the_reader_with_the_wire_identity, crates/rpc-rust-e2e/tests/enhanced_e2e.rs::an_enhanced_call_is_answered_through_the_related_sample_identity, crates/rpc/tests/cpp_rpc_zerodds_related_identity.rs::the_zerodds_binding_sends_and_reads_the_related_sample_identity, crates/java-omgdds/java/src/test/java/org/omg/dds/rpc/ZeroDdsParticipantTest.java::aWriteReturnsItsIdentityAndTheReaderSeesItWithTheRelatedOne

Status: done — in Rust, C++ und Java schreibt der Replier der Enhanced-Abbildung die Antwort mit dem Parameter, und der Requester liest ihn. Die Basic-Abbildung trägt die Identität im ReplyHeader (§7.8.1). Die Rust-Tests des Enhanced-Pfads lassen Requester und Replier auf einem Teilnehmer laufen (Zustellung innerhalb der Laufzeit); die Kodierung im Inline-QoS prüfen die Tests in crates/rtps.

§7.8.2 Wert ist die CDR-Kodierung von SampleIdentity

Spec: §7.8.2, S. 58 — “When present, it shall contain the CDR serialization of the SampleIdentity structure defined below.”

Repo: crates/rtps/src/inline_qos.rs::SampleIdentityBytes (to_bytes, from_bytes)

Tests: crates/rtps/src/inline_qos.rs::tests::sample_identity_layout_is_24_bytes, crates/rtps/src/inline_qos.rs::tests::sample_identity_roundtrip_le, crates/rtps/src/inline_qos.rs::tests::sample_identity_roundtrip_be

Status: done — 24 Oktette: GUID und Folgenummer in der Byte-Reihenfolge des Parameters.

§7.8.2 Wert gleich der Identität des Request-Samples

Spec: §7.8.2, S. 58 — “The value of the PID_RELATED_SAMPLE_IDENTITY in a reply message shall be identical to the sample identity (GUID, SN) of the request sample that triggered the reply.”

Repo: Rust: crates/rpc/src/replier.rs::Replier::receive_requests (RequestIdentity::from_inline_qos aus Writer-GUID und Folgenummer des DATA), Replier::send_reply und Replier::write_reply (write_related mit dieser Identität). C++: runtime/cpp/include/dds/rpc/core.hpp::Replier::send_reply mit Correlation::SAMPLE_IDENTITY (Writer::write_related). Java: runtime/java/src/main/java/org/zerodds/ddsrpc/ReplierImpl.java::sendReply (DataWriter.write(sample, relatedRequestId)). Commits: e305669e2c42 (Rust), 2bfb2786121b (C++), 771f12846807 und a2a9a67acb58 (Java)

Tests: crates/rpc/src/replier.rs::tests::an_enhanced_request_is_identified_by_its_data, crates/rpc/src/requester.rs::tests::an_enhanced_reply_is_correlated_by_its_related_identity, crates/rpc-rust-e2e/tests/enhanced_e2e.rs::an_enhanced_call_is_answered_through_the_related_sample_identity, crates/rpc/tests/runtime_e2e.rs::e2e_client_side_request_identity_is_the_one_the_reply_relates_to, crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together, crates/rpc/tests/java_rpc_runtime.rs::the_java_rpc_runtime_and_the_generated_services_run_together

Status: done — die Antwort trägt die Identität des Request-Samples, das der Reader des Replier geliefert hat; ein Request ohne Identität am DATA wird in Rust gezählt (Replier::unidentified_requests), nicht beantwortet.

Spec: §7.8.2, S. 58 — “The RELATED_SAMPLE_IDENTITY_INVALID constant is used to indicate an invalid/non-existing sample identity. […] RELATED_SAMPLE_IDENTITY_INVALID is defined as { GUID_UNKNOWN , SEQUENCENUMBER_UNKNOWN } both of which are defined in the [RTPS] specification.”

Repo: crates/rpc/src/common_types.rs::SampleIdentity::RELATED_SAMPLE_IDENTITY_INVALID (SampleIdentity::UNKNOWN ist ein Alias); runtime/cpp/include/dds/rpc/base.hpp::related_sample_identity_invalid; runtime/java/src/main/java/org/omg/dds/rpc/SampleIdentity.java::RELATED_SAMPLE_IDENTITY_INVALID. Commits: 2fe2b7cdea14, 6c1e75d0c116

Tests: crates/rpc/src/common_types.rs::tests::sample_identity_invalid_constant_is_rtps_unknown, crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together (Programm rpc_runtime_roundtrip.cpp: „the invalid related identity has SEQUENCENUMBER_UNKNOWN {-1, 0}“), crates/rpc/tests/java_rpc_runtime.rs::the_java_rpc_runtime_and_the_generated_services_run_together (Programm RpcRuntimeRoundtrip.java: „SEQUENCENUMBER_UNKNOWN.high is -1“ und „SEQUENCENUMBER_UNKNOWN.low is 0“)

Status: done — alle drei Laufzeiten haben die Konstante mit SEQUENCENUMBER_UNKNOWN = {high = -1, low = 0}; C++ und Java halten den „nicht gesetzt“-Wert (Folgenummer 0) davon getrennt. Die Programme von C++ (ea817b7746ef) und Java prüfen den Wert von related_sample_identity_invalid() und RELATED_SAMPLE_IDENTITY_INVALID; das Java-Programm prüft zusätzlich die Oktette im ReplyHeader. Die Programme sind im Code gelesen; ein Lauf auf dem Linux-Testhost nach diesen Commits steht aus.

§7.8.2.1 Identität des Requests am Service abrufen

Spec: §7.8.2.1, S. 58 — “This specification provides language bindings (7.11 Language Bindings) to retrieve the sample identity of the request in the form of a SampleIdentity object.”

Repo: runtime/cpp/include/dds/rpc.hpp (Replier::receive_requests, Sample::identity; gefüllt von Reader::take in runtime/cpp/include/dds/rpc/zerodds.hpp); runtime/java/src/main/java/org/omg/dds/rpc/Sample.java (identity; TakenSample.identity aus SampleImpl.identity() der Java PSM in ZeroDdsParticipant.Reader.take); Rust: crates/rpc/src/replier.rs::PendingRequest::identity. Commits: 2ea2abb7d843 (C++ Klassen), 2bfb2786121b (C++), 771f12846807 und a2a9a67acb58 (Java), c5af5c7c138e (Rust)

Tests: crates/rpc/tests/cpp_rpc_zerodds_related_identity.rs::the_zerodds_binding_sends_and_reads_the_related_sample_identity, crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together, crates/rpc/tests/java_rpc_runtime.rs::the_java_rpc_runtime_and_the_generated_services_run_together, crates/java-omgdds/java/src/test/java/org/omg/dds/rpc/ZeroDdsParticipantTest.java::aWriteReturnsItsIdentityAndTheReaderSeesItWithTheRelatedOne, crates/rpc/src/replier.rs::tests::receive_requests_and_send_reply_expose_the_identity

Status: done — C++ und Java (die Sprachbindungen der Spec) liefern die Identität des Requests am Sample; die Rust-Laufzeit liefert sie am PendingRequest.

§7.8.2.1 Identität des Requests in der Rust-Laufzeit

Spec: §7.8.2.1, S. 58 — wie oben.

Repo: crates/rpc/src/replier.rs (ReplierHandler::handle erhält nur den Wert; AsyncReplierHandler::on_request(replier, request, identity) und PendingRequest::identity tragen ein RequestIdentity); crates/rpc/src/request_identity.rs::RequestIdentity. Commit: c5af5c7c138e

Tests: crates/rpc/src/replier.rs::tests::receive_requests_and_send_reply_expose_the_identity, crates/rpc/src/replier.rs::tests::dispatch_async_hands_the_replier_and_the_identity_to_the_listener

Status: done — der synchrone Listener der Rust-Laufzeit (Weg 1) erhält nur den Wert des Requests, die Wege 2 und 3 erhalten die Identität. Die Spec definiert die Operation für C++ und Java; Rust ist keine ihrer Sprachbindungen. Die Moduldoku von request_identity.rs nennt eine Funktion current_request_identity, die es nicht gibt.

§7.8.2.2 Verwandte Identität am Client aus SampleInfo

Spec: §7.8.2.2, S. 58 — “This specification provides language bindings (7.11 Language Bindings) to retrieve the related sample identity of the reply from the reply SampleInfo in the form of a SampleIdentity object.”

Repo: runtime/cpp/include/dds/rpc.hpp (Sample::related_identity aus SampleInfo::related_identity; gefüllt von Reader::take in runtime/cpp/include/dds/rpc/zerodds.hpp aus dem Parameter, in der Basic-Abbildung von Requester::decode_reply aus dem ReplyHeader); runtime/java/src/main/java/org/omg/dds/rpc/Sample.java (relatedIdentity; TakenSample.relatedIdentity aus SampleImpl.relatedIdentity() der Java PSM). Commits: 2bfb2786121b (C++), 771f12846807 und a2a9a67acb58 (Java)

Tests: crates/rpc/tests/cpp_rpc_zerodds_related_identity.rs::the_zerodds_binding_sends_and_reads_the_related_sample_identity, crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together, crates/rpc/tests/java_rpc_runtime.rs::the_java_rpc_runtime_and_the_generated_services_run_together, crates/java-omgdds/java/src/test/java/org/omg/dds/rpc/ZeroDdsParticipantTest.java::aWriteReturnsItsIdentityAndTheReaderSeesItWithTheRelatedOne

Status: done — C++ und Java liefern die verwandte Identität am Reply-Sample aus der Information des Samples; in der Enhanced-Abbildung kommt sie aus PID_RELATED_SAMPLE_IDENTITY.

§7.8.2.2 Verwandte Identität in der Rust-Laufzeit

Spec: §7.8.2.2, S. 58 — wie oben.

Repo: crates/dcps/src/subscriber.rs::DataReader::take_with_wire (SampleWire::related_sample_identity); crates/rpc/src/requester.rs::Requester::tick (ordnet Replies der Enhanced-Abbildung über die verwandte Identität zu; Requester::uncorrelated_replies zählt Replies ohne sie). Commits: 8385434c2326, e305669e2c42

Tests: crates/dcps/src/subscriber.rs::tests::take_with_wire_hands_over_the_identity_and_the_related_identity, crates/rpc/src/requester.rs::tests::an_enhanced_reply_is_correlated_by_its_related_identity, crates/rpc/src/requester.rs::tests::an_enhanced_reply_without_a_related_identity_is_counted

Status: done — SampleInfo der DCPS-Schicht hat kein Feld dafür; die Laufzeit liest sie aus SampleWire. Der Rust-Requester gibt dem Aufrufer die Nutzlast des Replies, den er über diese Identität dem Request zugeordnet hat. Die Spec definiert die Operation für C++ und Java; Rust ist keine ihrer Sprachbindungen.

§7.8.2.3 Verwandte Identität beim Senden setzen

Spec: §7.8.2.3, S. 58 — “Before sending a reply, the service implementation needs to set the related sample identity of the reply sample. […] This specification provides language bindings to set the related sample identity when sending the reply to a request.”

Repo: runtime/cpp/include/dds/rpc/core.hpp::Replier::send_reply (mit related_request_id; Writer::write_related in runtime/cpp/include/dds/rpc/zerodds.hpp); runtime/java/src/main/java/org/omg/dds/rpc/Replier.java::sendReply (mit relatedRequestId; DataWriter.write(sample, related)); Rust: crates/rpc/src/replier.rs::Replier::send_reply (mit RequestIdentity) und crates/dcps/src/runtime.rs::DcpsRuntime::write_user_sample_related. Commits: 2bfb2786121b (C++), 771f12846807 und a2a9a67acb58 (Java), c5af5c7c138e (Rust)

Tests: crates/rpc/tests/cpp_rpc_zerodds_related_identity.rs::the_zerodds_binding_sends_and_reads_the_related_sample_identity, crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together, crates/rpc/tests/java_rpc_runtime.rs::the_java_rpc_runtime_and_the_generated_services_run_together, crates/rpc/src/replier.rs::tests::receive_requests_and_send_reply_expose_the_identity

Status: done — der Replier setzt die Identität des Requests beim Senden: in der Enhanced-Abbildung als PID_RELATED_SAMPLE_IDENTITY, in der Basic-Abbildung im ReplyHeader.


§7.9 Service Lifecycle

§7.9.1 Aktivierung durch Erzeugen von Service oder Replier

Spec: §7.9.1, S. 59 — “In Basic and Enhanced Service Mappings, when using the function-call style language binding, creating an instance of the Service type activates the service. Likewise, when using the request/reply style language binding, creating an instance of a Replier activates the service.”

Repo: crates/rpc/src/replier.rs::Replier::new; crates/lang-rules/src/emit/interface_rust.rs (Dispatcher mit serve); runtime/cpp/include/dds/rpc.hpp::Replier (Konstruktor mit ReplierParams); crates/lang-rules/src/emit/interface_cpp/calls.rs und crates/lang-rules/src/emit/interface_java/calls.rs (<I>Service über einem Replier, im Konstruktor angelegt). Commits: ec3707125a9b (C++), c512ee365514 (Java)

Tests: crates/rpc/src/replier.rs::tests::replier_new_creates_endpoints, crates/rpc-rust-e2e/tests/e2e.rs::the_generated_calculator_binding_runs_every_call, crates/rpc/tests/cpp_function_call.rs::the_generated_client_calls_the_generated_service, crates/rpc/tests/java_rpc_runtime.rs::the_generated_function_call_client_calls_the_generated_service

Status: done — das Erzeugen des Replier, von serve (Rust) und von <I>Service (C++, Java) aktiviert den Dienst.

§7.9.1 Aktivierung legt DataReader und DataWriter an

Spec: §7.9.1, S. 59 — “Service activation shall result in creation of the underlying DataReader and DataWriter entities and they shall be enabled.”

Repo: crates/rpc/src/replier.rs::Replier::from_topics (create_datareader, create_datawriter); runtime/cpp/include/dds/rpc.hpp::Replier; runtime/java/src/main/java/org/zerodds/ddsrpc/ReplierImpl.java

Tests: crates/rpc-rust-e2e/tests/e2e.rs::the_generated_calculator_binding_runs_every_call, crates/rpc/tests/cpp_function_call.rs::the_generated_client_calls_the_generated_service (Programm function_call_roundtrip.cpp: „creating the service creates its DataReader and DataWriter“)

Status: done — die Entitäten werden beim Erzeugen angelegt und sind aktiv.

§7.9.1 Aktivierter Dienst ist auffindbar

Spec: §7.9.1, S. 59 — “An activated service shall be discoverable.”

Repo: crates/rpc/src/replier.rs::Replier::from_topics (Topics unter dem Typnamen ${I}_Request und ${I}_Reply; in der Enhanced-Abbildung mit der Discovery-Erweiterung §7.6.2.1)

Tests: crates/rpc-rust-e2e/tests/e2e.rs::the_generated_calculator_binding_runs_every_call, crates/rpc-rust-e2e/tests/enhanced_e2e.rs::the_client_waits_for_the_service_instance_it_names, crates/rpc-rust-e2e/tests/lifecycle_e2e.rs::closing_a_service_deletes_its_entities

Status: done — der Client findet den aktivierten Dienst über die Discovery (service_matched); die Tests laufen mit Client und Dienst auf einem Teilnehmer.

§7.9.2.1 Function-call: Aufruf der Implementierung

Spec: §7.9.2.1, S. 59 — “Concrete implementations of the interface operations shall be invoked as a consequence of receiving requests. The operations must return a reply consistent with the language binding.”

Repo: crates/lang-rules/src/emit/interface_rust.rs (dispatcher_impl, dispatcher_handle_fn); crates/lang-rules/src/emit/interface_cpp/calls.rs und crates/lang-rules/src/emit/interface_java/calls.rs (<I>Service, ruft die Implementierung und übersetzt, was sie wirft, in einen Remote-Exception-Code). Commits: ec3707125a9b (C++), c512ee365514 (Java)

Tests: crates/rpc-rust-e2e/tests/e2e.rs::the_generated_calculator_binding_runs_every_call, crates/rpc/tests/cpp_function_call.rs::the_generated_client_calls_the_generated_service, crates/rpc/tests/cpp_enhanced_function_call.rs::the_generated_enhanced_client_calls_the_generated_enhanced_service, crates/rpc/tests/java_rpc_runtime.rs::the_generated_function_call_client_calls_the_generated_service, crates/lang-rules/tests/interface_bindings.rs::cpp_service_translates_what_the_implementation_throws

Status: done — in Rust, C++ und Java ruft der erzeugte Dienst die Implementierung der Operation auf und gibt die Antwort zurück.

§7.9.2.2 Drei Wege der Bearbeitung

Spec: §7.9.2.2, S. 59 — “The request/reply style language binding provides three mutually exclusive ways to process requests.”

Repo: —

Tests: —

Status: n/a (informative) — Einleitung; die drei Wege folgen als Items.

§7.9.2.2 Weg 1: synchroner Listener

Spec: §7.9.2.2, S. 59 — “1. A synchronous service listener callback can be installed during service activation. The synchronous callback must return the reply before the callback returns. It is invoked for each received request.”

Repo: crates/rpc/src/replier.rs (ReplierHandler, übergeben an Replier::new; Replier::tick; Replier::activate); runtime/cpp/include/dds/rpc.hpp (SimpleReplierListener, Replier::dispatch_requests, Aufruf bei Ankunft über Replier::Impl::listen); runtime/java/src/main/java/org/omg/dds/rpc/SimpleReplierListener.java (ListenerDelivery.ON_ARRIVAL). Commits: cd07b2221f07 (Rust), 05c799d7e041 (C++), 771f12846807 (Java)

Tests: crates/rpc/src/replier.rs::tests::tick_processes_request_and_writes_reply, crates/rpc-rust-e2e/tests/lifecycle_e2e.rs::a_call_is_answered_without_anyone_ticking, crates/rpc/tests/cpp_rpc_zerodds_listener.rs::the_zerodds_reader_calls_its_callback_on_arrival_and_not_after_removal, crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together, crates/rpc/tests/java_rpc_runtime.rs::the_java_rpc_runtime_and_the_generated_services_run_together

Status: done — der Listener wird beim Erzeugen übergeben, gibt die Antwort zurück und wird bei Ankunft jedes Requests aufgerufen (Rust: activate; Java: je nach ListenerDelivery, Vorgabe ON_ARRIVAL).

§7.9.2.2 Weg 2: asynchroner Listener mit dem Replier

Spec: §7.9.2.2, S. 59 — “2. An asynchronous service listener callback can be installed during service activation. The asynchronous callback does not return the reply. The callback receives a handle to the Replier instance and the Replier API can be used to retrieve the requests and send the replies.”

Repo: crates/rpc/src/replier.rs (AsyncReplierHandler, Replier::activate_async, Replier::dispatch_async); runtime/cpp/include/dds/rpc.hpp (ReplierListener); runtime/java/src/main/java/org/omg/dds/rpc/ReplierListener.java. Commits: c5af5c7c138e und cd07b2221f07 (Rust), 05c799d7e041 (C++), 771f12846807 (Java)

Tests: crates/rpc/src/replier.rs::tests::dispatch_async_hands_the_replier_and_the_identity_to_the_listener, crates/rpc-rust-e2e/tests/lifecycle_e2e.rs::the_asynchronous_listener_is_called_as_the_request_arrives, crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together, crates/rpc/tests/java_rpc_runtime.rs::the_java_rpc_runtime_and_the_generated_services_run_together

Status: done — der Callback erhält den Replier und gibt keine Antwort zurück; in allen drei Laufzeiten.

§7.9.2.2 Weg 3: Requests über die API des Replier abholen

Spec: §7.9.2.2, S. 59 — “3. The Replier API may be used to retrieve the requests and send replies.”

Repo: crates/rpc/src/replier.rs (Replier::receive_requests, Replier::send_reply, Replier::send_exception); runtime/cpp/include/dds/rpc.hpp (Replier::receive_requests, Replier::send_reply); runtime/java/src/main/java/org/omg/dds/rpc/Replier.java (receiveRequests, sendReply). Commits: c5af5c7c138e (Rust), 2ea2abb7d843 (C++), 771f12846807 (Java)

Tests: crates/rpc/src/replier.rs::tests::receive_requests_and_send_reply_expose_the_identity, crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together, crates/rpc/tests/java_rpc_runtime.rs::the_java_rpc_runtime_and_the_generated_services_run_together

Status: done — die drei Laufzeiten haben das Abholen der Requests und das Senden der Replies. Dass die Namen der Operationen von denen der normativen C++-Datei abweichen (take_request, read_request, wait_for_requests), steht im Item „§7.11.1 Maschinenlesbare Dateien für C++“.

§7.9.2.2 Listener werden bei Ankunft eines Requests aufgerufen

Spec: §7.9.2.2, S. 59 — wie die drei Items oben.

Repo: crates/rpc/src/replier.rs::Replier::activate, Replier::activate_async (Listener am Request-Reader); runtime/cpp/include/dds/rpc.hpp::Replier (Konstruktor ruft Impl::listen; Replier::on_arrival); runtime/java/src/main/java/org/zerodds/ddsrpc/ReplierImpl.java und ListenerDelivery.java (ON_ARRIVAL über DataReader.setDataAvailableListener). Commits: cd07b2221f07 (Rust), 05c799d7e041 (C++), 771f12846807 (Java)

Tests: crates/rpc-rust-e2e/tests/lifecycle_e2e.rs::a_call_is_answered_without_anyone_ticking, crates/rpc-rust-e2e/tests/lifecycle_e2e.rs::the_asynchronous_listener_is_called_as_the_request_arrives, crates/rpc/tests/cpp_rpc_zerodds_listener.rs::the_zerodds_reader_calls_its_callback_on_arrival_and_not_after_removal, crates/rpc/tests/java_rpc_runtime.rs::the_java_rpc_runtime_and_the_generated_services_run_together (Programm RpcRuntimeRoundtrip.java, Abschnitt über die Java PSM: „the replier listener ran on arrival“)

Status: done — in allen drei Laufzeiten ruft die Laufzeit den Listener bei Ankunft eines Requests auf; die Anwendung muss tick(), dispatch_requests() oder dispatchRequests() nicht aufrufen. Java kennt zusätzlich ListenerDelivery.ON_PUMP für eine Anbindung, die nicht benachrichtigen kann.

§7.9.3 Deaktivierung löscht DataReader und DataWriter

Spec: §7.9.3, S. 59 — “Deleting (subject to language binding) the service instance deactivates the service. In Java language binding, Closeable.Close() deactivates the service. In C++ language binding, the destructor of the service implementation shall deactivate the service. Deactivation shall delete the underlying DDS entities (i.e., DataReader and DataWriter only).”

Repo: crates/rpc/src/replier.rs::Replier::close (der letzte Handle löscht die Entitäten); runtime/cpp/include/dds/rpc.hpp::Replier::close (gibt Reader und Writer frei; der Destruktor der Anbindung ruft zerodds_writer_destroy und zerodds_reader_destroy); runtime/java/src/main/java/org/zerodds/ddsrpc/ReplierImpl.java::close und runtime/java/src/main/java/org/zerodds/ddsrpc/RequesterImpl.java::close (DomainParticipant.deleteWriter, deleteReader). Commits: cd07b2221f07 (Rust), ec3707125a9b (C++), 530a4c8dee0a und 771f12846807 (Java)

Tests: crates/rpc-rust-e2e/tests/lifecycle_e2e.rs::closing_a_service_deletes_its_entities, crates/rpc/src/requester.rs::tests::duplicate_instance_name_freed_after_drop, crates/rpc/tests/cpp_function_call.rs::the_generated_client_calls_the_generated_service (Programm function_call_roundtrip.cpp: „destroying the last copy deletes the DataReader and the DataWriter“), crates/rpc/tests/java_rpc_runtime.rs::the_java_rpc_runtime_and_the_generated_services_run_together (Programm RpcRuntimeRoundtrip.java: „closing the service deleted its replier’s DataWriter and DataReader“)

Status: done — Deaktivierung löscht in Rust, C++ und Java DataReader und DataWriter und sonst keine Entität. Der Rust-Test prüft, dass der Peer das Match verliert.

§7.9.3 Deaktivierung in Java und im erzeugten C++

Spec: §7.9.3, S. 59 — wie oben.

Repo: runtime/java/src/main/java/org/omg/dds/rpc/RPCEntity.java (Closeable); runtime/java/src/main/java/org/zerodds/ddsrpc/ZeroDdsParticipant.java (deleteWriter, deleteReader schließen die Entitäten der Java PSM); runtime/cpp/include/dds/rpc.hpp::ServiceEndpoint::close; crates/lang-rules/src/emit/interface_cpp/calls.rs (<I>Service hält den Replier, der Destruktor gibt ihn frei). Commits: 530a4c8dee0a, ec3707125a9b (C++), c512ee365514 (Java), a2a9a67acb58

Tests: crates/rpc/tests/cpp_function_call.rs::the_generated_client_calls_the_generated_service, crates/rpc/tests/java_rpc_runtime.rs::the_generated_function_call_client_calls_the_generated_service, crates/rpc/tests/java_rpc_runtime.rs::the_java_rpc_runtime_and_the_generated_services_run_together

Status: done — close() in Java und der Destruktor oder close() der erzeugten C++-Klassen löschen DataReader und DataWriter. Die Programme der Tests zählen die gelöschten Entitäten einer aufzeichnenden Anbindung; die Löschung der Entitäten der Java PSM durch ZeroDdsParticipant ist aus dem Code gelesen (psm.close()), nicht von einem Test geprüft.


§7.10 Service QoS

§7.10 QoS-Annotation am Interface

Spec: §7.10, S. 59 — “Both Basic and Enhanced Service Mappings allow QoS annotation with an interface.”

Repo: —

Tests: —

Status: n/a (informative) — Einleitung; die Annotation steht in §7.10.1.

§7.10.1 Annotation @Qos mit RequestProfile und ReplyProfile

Spec: §7.10.1, S. 59–60 — “To set the specific Qos for an interface, the annotation @Qos shall be used. It is defined as follows. @annotation local interface Qos { attribute string RequestProfile; attribute string ReplyProfile; };”

Repo: crates/rpc/src/annotations.rs (lower_single, Zweig "Qos"; RpcAnnotation::Qos; LoweredRpc::qos_profiles); @Qos ist als Annotation der Spec vordefiniert (Commit 6c7f585a36ee); crates/lang-rules/src/adapter/interface.rs (qos_request_profile, qos_reply_profile); crates/lang-rules/src/emit/interface_rust.rs::declared_qos_fn (new_with_declared_qos, serve_with_declared_qos); crates/lang-rules/src/emit/interface_cpp/calls.rs::defaults_method; crates/lang-rules/src/emit/interface_java/calls.rs (qosProfiles). @RPCInterfaceQos(profile = …) bleibt als Erweiterung neben @Qos. Commits: e0eb1bf9c607 (Rust), ec3707125a9b (C++), c512ee365514 (Java)

Tests: crates/rpc/src/annotations.rs::tests::the_spec_annotations_need_no_declaration, crates/rpc/src/qos_profile.rs::tests::the_request_and_the_reply_profile_apply_to_their_own_endpoints, crates/lang-rules/tests/interface_rust_binding.rs::the_qos_the_interface_declares_is_applied_by_a_constructor, crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together (Programm rpc_runtime_roundtrip.cpp: Profile der Params)

Status: done — @Qos mit RequestProfile und ReplyProfile wird erkannt und erreicht die Endpunkte in Rust, C++ und Java; ein fehlendes ReplyProfile lässt beide Richtungen aus dem RequestProfile bauen.

§7.10.1 Profil als URL, file:// Pflicht, #library_name

Spec: §7.10.1, S. 60 — “The profile attributes are string URLs of the form: ://path/resource where protocol, “:”, “//” and path are optional. Support for the file:// protocol is mandatory. If the protocol:// is omitted, the string attributes are interpreted as if the protocol is file://. The URL may end with an optional library name. The profile filename and library_name are separated by a #.”

Repo: crates/rpc/src/qos_profile.rs::RpcQos::from_qos_url (split_qos_url); crates/zerodds-c-api/src/rpc_profile_ffi.rs::zerodds_endpoint_qos_from_profile_url (C++: runtime/cpp/include/dds/rpc/zerodds.hpp); runtime/java/src/main/java/org/omg/dds/rpc/RpcQos.java::fromUrl. Commits: 152906e062f1 (Rust), a0d1af7efd77 (c-api), 7253f8222589 (C++), 771f12846807 (Java)

Tests: crates/rpc/src/qos_profile.rs::tests::split_qos_url_defaults_the_protocol_to_file, crates/rpc/src/qos_profile.rs::tests::from_qos_url_reads_the_file_and_applies_the_library, crates/zerodds-c-api/tests/rpc_qos.rs::a_profile_url_resolves_the_named_library_over_the_rpc_defaults, crates/rpc/tests/cpp_rpc_zerodds_qos.rs::the_zerodds_binding_carries_the_rpc_qos_to_the_c_api, crates/rpc/tests/java_rpc_runtime.rs::the_java_rpc_runtime_and_the_generated_services_run_together (Programm RpcRuntimeRoundtrip.java: RpcQos.fromUrl)

Status: done — file:// wird gelesen, ohne Protokoll gilt file://, # trennt Dateinamen und Bibliothek; ein anderes Protokoll ist ein Fehler, kein Abruf.

§7.10.1 Profile im Format von DDS4CCM

Spec: §7.10.1, S. 60 — “The QoS profiles are XML QoS Profiles as defined in the [DDS4CCM] specification.”

Repo: crates/rpc/src/qos_profile.rs::RpcQos::from_xml_profile und RpcQos::from_qos_url (Profile aus zerodds-xml, DDS-XML 1.0: <dds><qos_library><qos_profile>); Commit: 9b74a81b0a98

Tests: crates/rpc/src/qos_profile.rs::tests::from_xml_profile_overrides_history_depth, crates/rpc/src/qos_profile.rs::tests::from_xml_profile_follows_base_name_chain, crates/rpc/tests/runtime_e2e.rs::e2e_qos_profile_from_xml_drives_history_depth

Status: done — DDS4CCM 1.1 §7.4.2.3 setzt <qos_profile> unmittelbar unter <dds> und kennt die Kurzform eines einzelnen <datawriter_qos name="…"> (§7.4.2.3.3); qos_library kommt dort nicht vor. DDS-XML 1.0 kennt diese Form nicht, crates/xml führt sie deshalb als Vendor-Form: der Standard lehnt sie mit einem Fehler ab, der sie nennt, VendorForms::Accept liest sie in die Bibliothek CCM_LIBRARY ((dds)) und meldet jede (crates/xml/src/qos_parser.rs::parse_ccm_top_level_profile). RpcQos::from_qos_url und zerodds_endpoint_qos_from_profile_url lesen die Dateien mit dieser Einstellung, weil §7.10.1 DDS4CCM als Format nennt. Commit 07a65cfe5cde. Tests: crates/xml/src/zerodds_xml.rs::tests::ccm_profiles_directly_under_dds_are_a_vendor_form, a_qos_library_and_ccm_profiles_can_share_a_document, crates/rpc/src/qos_profile.rs::tests::from_qos_url_reads_a_ddscm_profile_file, crates/zerodds-c-api/tests/rpc_qos.rs (auf dem Linux-Testhost gelaufen für crates/xml).

§7.10.2 Vorgaben ohne Angabe

Spec: §7.10.2, S. 60 — “When no QoS is specified, default QoS are in effect. […] The users may modify the mutable QoS policies at run-time.”

Repo: crates/rpc/src/qos_profile.rs::RpcQos::default_basic; runtime/cpp/include/dds/rpc/base.hpp::EndpointQos; runtime/java/src/main/java/org/omg/dds/rpc/RpcQos.java::defaults

Tests: crates/rpc/src/qos_profile.rs::tests::default_is_basic, crates/rpc/src/qos_profile.rs::tests::default_basic_matches_spec_710_2, crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together (Programm: „the defaults are §7.10.2’s“), crates/rpc/tests/java_rpc_runtime.rs::the_java_rpc_runtime_and_the_generated_services_run_together (Programm: „§7.10.2: RELIABLE, KEEP_ALL, VOLATILE“)

Status: done — ohne Angabe gelten in Rust, C++ und Java die Vorgaben der drei Richtlinien (folgende Items). Die Änderung zur Laufzeit steht im nächsten Item.

§7.10.2 Änderbare QoS zur Laufzeit

Spec: §7.10.2, S. 60 — wie oben.

Repo: crates/rpc/src/replier.rs::Replier::set_qos, crates/rpc/src/requester.rs::Requester::set_qos; runtime/cpp/include/dds/rpc.hpp (Requester::set_qos, Replier::set_qos, ServiceEndpoint::set_qos) über zerodds_writer_set_qos und zerodds_reader_set_qos der C-API; runtime/java/src/main/java/org/omg/dds/rpc/Requester.java::setQos, runtime/java/src/main/java/org/omg/dds/rpc/Replier.java::setQos. Commits: 5e31aafecaaf (Rust), 7253f8222589 (C++), 19814c9f2e93 (c-api: nur DEADLINE und LIFESPAN änderbar), 771f12846807 (Java), 04b1846d0ee5 (Java: ZeroDdsParticipant reicht die Änderung an die PSM weiter)

Tests: crates/rpc/tests/runtime_e2e.rs::e2e_set_qos_changes_the_mutable_policies_at_run_time, crates/zerodds-c-api/tests/rpc_qos.rs::the_mutable_policies_of_a_live_endpoint_change_and_the_immutable_ones_are_refused, crates/rpc/tests/cpp_rpc_zerodds_qos.rs::the_zerodds_binding_carries_the_rpc_qos_to_the_c_api, crates/rpc/tests/java_rpc_runtime.rs::the_java_rpc_runtime_and_the_generated_services_run_together

Status: done — Rust und C++ ändern die änderbaren Richtlinien und verweigern die unveränderbaren. In Java gibt ZeroDdsParticipant.Writer.setQos (und Reader.setQos) die geänderte QoS an DataWriterImpl.setQos bzw. DataReaderImpl.setQos der PSM weiter; die PSM wendet die Änderung einer änderbaren Richtlinie (DEADLINE, LIFESPAN) an und weist eine unveränderbare mit ImmutablePolicyException ab (QosRules.checkChange, 8bc25e5d19b1), was die Laufzeit als RemoteUnsupportedError meldet. Test: crates/rpc/tests/java/RpcRuntimeRoundtrip.java::overTheJavaPsm (DEADLINE ändert sich, RELIABILITY nicht; braucht ein JDK). Der frühere Satz, die PSM verweigere jede Änderung, galt vor 8bc25e5d19b1.

§7.10.2 Reliability RELIABLE

Spec: §7.10.2, S. 60 — “Reliability DDS_RELIABLE_RELIABILITY_QOS”.

Repo: crates/rpc/src/qos_profile.rs::RpcQos::default_basic; runtime/cpp/include/dds/rpc/base.hpp::EndpointQos; runtime/java/src/main/java/org/omg/dds/rpc/RpcQos.java::defaults

Tests: crates/rpc/src/qos_profile.rs::tests::default_basic_matches_spec_710_2, crates/rpc/src/qos_profile.rs::tests::writer_qos_carries_reliability_and_history, crates/rpc/src/qos_profile.rs::tests::reader_qos_carries_reliability

Status: done — Vorgabe RELIABLE in Rust, C++ und Java.

§7.10.2 History KEEP_ALL

Spec: §7.10.2, S. 60 — “History DDS_KEEP_ALL_HISTORY_QOS”.

Repo: crates/rpc/src/qos_profile.rs::RpcQos::default_basic, RpcQos::default_enhanced (DEFAULT_HISTORY_QOS); runtime/cpp/include/dds/rpc/base.hpp::EndpointQos; runtime/java/src/main/java/org/omg/dds/rpc/RpcQos.java::defaults. Commit: ff6353d0ef20

Tests: crates/rpc/src/qos_profile.rs::tests::default_basic_matches_spec_710_2, crates/rpc/src/qos_profile.rs::tests::default_enhanced_uses_the_same_history, crates/rpc/src/qos_profile.rs::tests::writer_qos_carries_reliability_and_history

Status: done — Vorgabe KEEP_ALL in Rust, C++ und Java.

§7.10.2 Durability VOLATILE

Spec: §7.10.2, S. 60 — “Durability DDS_VOLATILE_DURABILITY_QOS”.

Repo: crates/rpc/src/qos_profile.rs::RpcQos::default_basic; runtime/cpp/include/dds/rpc/base.hpp::EndpointQos; runtime/java/src/main/java/org/omg/dds/rpc/RpcQos.java::defaults

Tests: crates/rpc/src/qos_profile.rs::tests::default_basic_matches_spec_710_2

Status: done — Vorgabe VOLATILE in Rust, C++ und Java.


§7.11 Language Bindings

§7.11 Figure 7.5 — Vererbung der RPC-Entitäten

Spec: §7.11, S. 60, Figure 7.5 — RPCEntity ist Basis von Server, ServiceEndpoint, Replier und ServiceProxy; ServiceProxy ist Basis von Requester und ClientEndpoint; ServiceEndpoint von Service; ClientEndpoint von Client.

Repo: runtime/cpp/include/dds/rpc.hpp (RPCEntity, ServiceProxy, Requester, Replier, ServiceEndpoint, ClientEndpoint, Service, Client); runtime/java/src/main/java/org/omg/dds/rpc/ (RPCEntity, ServiceProxy, Requester, Replier, ServiceEndpoint, ClientEndpoint, Service, Client). Commit: 2ea2abb7d843 (C++)

Tests: crates/rpc/tests/class_summaries_are_declared.rs::the_cpp_runtime_declares_every_class_of_the_two_summaries, crates/rpc/tests/class_summaries_are_declared.rs::the_java_package_declares_every_type_of_the_two_summaries, crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together (Programm rpc_runtime_roundtrip.cpp: static_assert(std::is_base_of<…>) für alle Beziehungen der Figur), crates/rpc/tests/java_rpc_runtime.rs::the_java_entities_are_interfaces_and_the_runtime_makes_services_and_clients (Programm crates/rpc/tests/java/RpcInheritanceTest.java: Server und ClientEndpoint)

Status: done — C++: rpc_runtime_roundtrip.cpp prüft beim Übersetzen jede Beziehung der Figur mit std::is_base_of, einschließlich Server (f8116b6debc1). Java: RpcInheritanceTest.java prüft die Basisschnittstellen der Figur Glied für Glied (267cd1cb4793).

§7.11 Server als RPCEntity

Spec: §7.11, S. 60, Figure 7.5 — wie oben.

Repo: runtime/cpp/include/dds/rpc.hpp::Server (class Server : public RPCEntity, is_null(), close(), run(), run(Duration)); runtime/java/src/main/java/org/omg/dds/rpc/Server.java (Server extends RPCEntity, Runnable; run, getDefaultServiceParams, isNull, close). Commits: f8116b6debc1 (C++), 17cc6c7ad2a5 (Java)

Tests: crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together (Programm rpc_runtime_roundtrip.cpp: static_assert(std::is_base_of<dds::rpc::RPCEntity, dds::rpc::Server>)), crates/rpc/tests/java_rpc_runtime.rs::the_java_entities_are_interfaces_and_the_runtime_makes_services_and_clients (Programm crates/rpc/tests/java/RpcInheritanceTest.java: „Server extends RPCEntity“, „Server extends Runnable“, run, getDefaultServiceParams, isNull, close)

Status: done — Server ist in C++ und Java ein RPCEntity, wie die normativen Dateien function_call.h und runtime/java/src/main/java/org/omg/dds/rpc/Server.java es deklarieren. C++: is_null(), close(), run() und run(Duration); add weist einen Dienst ab, den ein anderer Server hält (IllegalOperationError). Java: ServerImpl.add weist null, einen geschlossenen und einen schon gebundenen Dienst ab. Die Tests sind im Code gelesen; ein Lauf auf dem Linux-Testhost nach diesen Commits steht aus.

§7.11.1 Maschinenlesbare Dateien für C++

Spec: §7.11.1, S. 61 — “The machine readable files associated with this specification represent the normative language bindings for C++.”

Repo: runtime/cpp/include/dds/rpc/normative/ (die drei Header unverändert), runtime/cpp/include/dds/rpc/vendor_dependent.h, runtime/cpp/include/dds/rpc/request_reply.hpp, runtime/cpp/include/dds/rpc/function_call.hpp, runtime/cpp/include/dds/rpc/core.hpp, runtime/cpp/include/dds/rpc/base.hpp, runtime/cpp/include/dds/rpc.hpp; verglichen mit den Headern request_reply, function_call und sample aus omg-dds-rpc-cxx.zip

Tests: crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together (Programm rpc_runtime_roundtrip.cpp, Namespace signatures), crates/rpc/tests/cpp_normative_headers.rs::the_shipped_headers_are_the_omg_files, crates/rpc/tests/cpp_normative_headers.rs::the_normative_headers_compile_against_vendor_dependent_h, crates/rpc/tests/cpp_normative_headers.rs::a_program_against_the_normative_headers_runs_against_libzerodds

Status: done — request_reply.h, function_call.h und sample.h aus omg-dds-rpc-cxx.zip liegen unverändert in runtime/cpp/include/dds/rpc/normative/ (NOTICE, SHA-256 in omg-dds-rpc-cxx.sha256). vendor_dependent.h füllt, was die Header „vendor dependent“ nennen (OMG_DDS_RPC_REFERENCE_IMPLEMENTATION, dds::dds_entity_traits, details::vendor_dependent<T>, Vorwärtsdeklarationen). request_reply.hpp und function_call.hpp definieren die Klassen der Header als Handles auf die Implementierungsklassen in dds::rpc::core (core.hpp, base.hpp); rpc.hpp ist die Schicht darüber (Service, Client, RPCRuntime, add(Server&, …)), und die erzeugten Header binden sie ein (f2fc6695f1e9, c56e3e21d7cc, 82edc9e2fb65, 1052b15cbe41). Gemessen auf dem Linux-Testhost: die Übersetzungseinheit aus beiden normativen Headern, die vorher 254 Fehler hatte, übersetzt mit -Wall -Wextra -Werror; ein Programm, das gegen die normativen Header geschrieben ist (normative_roundtrip.cpp), führt Request/Reply (Requester, Replier) und einen Funktionsaufruf (ClientEndpoint/ServiceEndpoint des erzeugten Clients und Dienstes) gegen libzerodds aus (8527130ff3fb). Die SHA-256-Summen der drei Dateien stehen in omg-dds-rpc-cxx.sha256; der Vergleich mit dem Zip läuft, wo ZD_DDS_RPC_CXX_ZIP, internal/standards/cache/omg/ oder ~/.cache/zerodds-spec/ es nennen; ob es auf dem Testhost dort lag, wurde nicht geprüft. Zwei Fehler der OMG-Header werden umgangen, nicht geändert: der private Destruktor von ListenerBase (beim Einlesen steht vor virtual ein public:, vendor_dependent.h) und RequesterParams vor seiner Deklaration. Die Header geben Server kein add, run_once und size; dds::rpc::add, run_once und size in rpc.hpp ergänzen sie.

§7.11.1.1.1 Request/Reply: IDL-Strukturen des Benutzers oder synthetisierte

Spec: §7.11.1.1.1, S. 61 — “The request-reply style language binding for the Basic Service Mapping shall use either the user-defined IDL structs directly or the structs synthesized from an IDL interface.”

Repo: runtime/cpp/include/dds/rpc.hpp (Requester<TReq, TRep>, Replier<TReq, TRep> über dds_type_traits); crates/lang-rules/src/emit/interface_cpp.rs::requester_alias. Commit: ad892a10764a

Tests: crates/lang-rules/tests/interface_bindings.rs::cpp_binds_the_requester_and_replier_of_seven_eleven_one_one_one, crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together

Status: done — Requester und Replier nehmen die Strukturen des Benutzers und die synthetisierten über dds_type_traits; der Generator bindet beide (CalculatorRequester, CalculatorReplier).

§7.11.1.1.1 Abbildung von IDL nach C++ nach [IDL35]

Spec: §7.11.1.1.1, S. 61 — “The IDL shall be mapped to C++ types as defined in [IDL35] (including the vendor-specific mappings for DDS v1.3).”

Repo: crates/lang-rules/src/adapter/cpp.rs (Vorgabe: eigene Abbildung); crates/lang-rules/src/adapter/cpp_psm.rs (--cpp-mapping psm: Abbildung nach DDS-PSM-Cxx §8.1); tools/idlc/src/main.rs (Option --cpp-mapping). Commit: 1db807cbf0fb

Tests: tools/idlc/src/generate.rs::tests::the_psm_mapping_is_a_layer_over_the_native_types, crates/rpc/tests/cpp_function_call.rs::the_generated_client_calls_the_generated_service, crates/rpc/tests/cpp_enhanced_function_call.rs::the_generated_enhanced_client_calls_the_generated_enhanced_service, crates/lang-rules/tests/interface_cpp_psm_types.rs::the_enhanced_futures_hold_the_applications_types

Status: done — Die Voreinstellung ist --cpp-mapping psm (CppMapping::Psm in adapter/cpp.rs); --cpp-mapping native ist eine benannte Einstellung. Die Klassen <I>, <I>Async, Client und Dienst schreiben die Typen von DDS-PSM-Cxx Table 7.1 (std::wstring, std::map, ::dds::core::array) in den Namespaces der IDL und wandeln über zerodds::psm::Conv in die Topic-Typen, die nativ in zd_native bleiben (93962a6aac1c, Test interface_cpp_psm_types.rs::the_topic_types_are_native_and_the_classes_are_the_applications). Die future-Typen der _async-Operationen halten die Typen der Anwendung, in der Basic- und in der Enhanced-Abbildung (1240c62e4ec6). Die C++-Tests dieses Pakets laufen unter der Voreinstellung (cpp_function_call, cpp_enhanced_function_call, cpp_rpc_real_library, cpp_rpc_runtime). Nicht geprüft: [IDL35] liegt nicht im Cache; die Klausel nennt für die Typen DDS-PSM-Cxx Table 7.1.

§7.11.1.1.1 Templates für Senden, Empfangen, Anlegen, Initialisieren, Zerstören

Spec: §7.11.1.1.1, S. 61 — “The Requester, Replier, Sample, SampleRef, WriteSample, and WriteSampleRef templates provide a uniform interface to send, receive, allocate, initialize, and destroy data.”

Repo: runtime/cpp/include/dds/rpc.hpp (Sample, SampleRef, WriteSample, WriteSampleRef, Requester, Replier)

Tests: crates/rpc/tests/class_summaries_are_declared.rs::the_cpp_runtime_declares_every_class_of_the_two_summaries, crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together

Status: done — die sechs Templates sind vorhanden und tragen Senden (Requester::send_request), Empfangen (Replier::receive_requests, Requester::receive_reply), Anlegen und Initialisieren (Konstruktoren) und Zerstören (Destruktoren). Der Abgleich der einzelnen Operationen mit sample.h steht im Item „§7.11.1 Maschinenlesbare Dateien für C++“.

§7.11.1.1.2 Function-call: Topic-Typen nach DDS-Cxx-PSM

Spec: §7.11.1.1.2, S. 61 — “The function-call style language binding for the Basic Service Mapping shall use the structs (and unions) synthesized from the user-defined IDL interface […] The topic-types shall be mapped to C++ types as per defined in [DDS-Cxx-PSM] with the following additional rules”.

Repo: crates/lang-rules/src/emit/interface_cpp.rs::declare; crates/lang-rules/src/adapter/cpp.rs::cpp_value_type

Tests: crates/lang-rules/tests/interface_bindings.rs::cpp_declares_the_topic_types_of_seven_five, crates/rpc/tests/cpp_function_call.rs::the_generated_client_calls_the_generated_service, crates/lang-rules/tests/interface_cpp_psm_types.rs::the_enhanced_futures_hold_the_applications_types

Status: done — Ganzzahlen, string, sequence, T[N], wstring und map stehen in der Voreinstellung wie in DDS-Cxx-PSM Table 7.1 (1db807cbf0fb, 93962a6aac1c; Test interface_cpp_psm_types.rs::the_interface_spells_the_types_of_table_7_1). Die Voreinstellung ist --cpp-mapping psm (CppMapping::Psm in adapter/cpp.rs); --cpp-mapping native ist eine benannte Einstellung. Die Topic-Typen bleiben nativ (zd_native), die Futures der _async-Operationen halten die Typen der Anwendung (1240c62e4ec6).

§7.11.1.1.2 Regel 1: ${interface} und ${interface}Async im Namespace des Moduls

Spec: §7.11.1.1.2, S. 61 — “1. Each IDL interface shall map to an abstract class named “interface” andanabstractclassnamed“{interface}Async” in the same namespace corresponding to the module of the interface. If there is no module, no C++ namespace is generated.”

Repo: crates/lang-rules/src/emit/interface_cpp.rs (sync_interface, async_interface). Commit: ad892a10764a

Tests: crates/lang-rules/tests/interface_bindings.rs::cpp_declares_the_two_abstract_classes_of_rule_one

Status: done — zwei abstrakte Klassen im Namespace des Moduls; ohne Modul kein Namespace.

§7.11.1.1.2 Regel 2: öffentlicher virtueller Destruktor

Spec: §7.11.1.1.2, S. 61 — “2. Both “interface” and“{interface}Async” abstract classes shall have a public virtual destructor.”

Repo: crates/lang-rules/src/emit/interface_cpp.rs (sync_interface, async_interface). Commit: ad892a10764a

Tests: crates/lang-rules/tests/interface_bindings.rs::cpp_declares_the_two_abstract_classes_of_rule_one

Status: done — virtual ~<I>() = default; und virtual ~<I>Async() = default;.

§7.11.1.1.2 Regel 3: SupportType, RequestType, ReplyType

Spec: §7.11.1.1.2, S. 61 — “3. Both “interface” and“{interface}Async” abstract classes shall have public SupportType, RequestType, and ReplyType typedefs for “interfaceSupport,”“{interface}_Request,” and “${interface}_Reply” types.”

Repo: crates/lang-rules/src/emit/interface_cpp.rs (sync_interface, async_interface, support_class). Commit: ad892a10764a

Tests: crates/lang-rules/tests/interface_bindings.rs::cpp_declares_the_two_abstract_classes_of_rule_one

Status: done — beide Klassen haben SupportType, RequestType und ReplyType.

§7.11.1.1.2 Regel 4: AsyncInterfaceType

Spec: §7.11.1.1.2, S. 61 — “4. The “interface” abstractclassshallcontainapublicAsyncInterfaceTypetypedeffor“{interface}Async.””

Repo: crates/lang-rules/src/emit/interface_cpp.rs::sync_interface; Commit ad892a10764a.

Tests: crates/lang-rules/tests/interface_bindings.rs::cpp_declares_the_two_abstract_classes_of_rule_one

Status: done

§7.11.1.1.2 Regel 5: InterfaceType

Spec: §7.11.1.1.2, S. 61 — “5. The “interfaceAsync” abstractclassshallcontainapublicInterfaceTypetypedeffor“{interface}.””

Repo: crates/lang-rules/src/emit/interface_cpp.rs::async_interface; Commit ad892a10764a.

Tests: crates/lang-rules/tests/interface_bindings.rs::cpp_declares_the_two_abstract_classes_of_rule_one

Status: done

§7.11.1.1.2 Regel 6: rein virtuelle Funktionen für Operationen und Attribute

Spec: §7.11.1.1.2, S. 61 — “6. The “${interface}” abstract class shall contain public pure virtual functions for all the operations and attributes defined in the IDL using the following rules”.

Repo: crates/lang-rules/src/emit/interface_cpp.rs (sync_interface, sync_method, attribute_method); Commit ad892a10764a.

Tests: crates/lang-rules/tests/interface_bindings.rs::cpp_declares_the_synchronous_operations_of_rule_six, crates/lang-rules/tests/interface_bindings.rs::cpp_names_an_attribute_accessor_after_the_attribute

Status: done

§7.11.1.1.2 Regel 6a: Name der Operation

Spec: §7.11.1.1.2, S. 61 — “a. The name of the function shall be same as the name of the IDL operation.”

Repo: crates/lang-rules/src/emit/interface_cpp.rs::sync_method; Commit ad892a10764a.

Tests: crates/lang-rules/tests/interface_bindings.rs::cpp_declares_the_synchronous_operations_of_rule_six

Status: done

§7.11.1.1.2 Regel 6b: Zahl und Reihenfolge der Argumente

Spec: §7.11.1.1.2, S. 61 — “b. The number and the order of the arguments shall be as defined in the IDL.”

Repo: crates/lang-rules/src/emit/interface_cpp.rs::sync_method; Commit ad892a10764a.

Tests: crates/lang-rules/tests/interface_bindings.rs::cpp_declares_the_synchronous_operations_of_rule_six

Status: done — Regel 6h stellt bei konstruierter Rückgabe cxx_return vor die Argumente.

§7.11.1.1.2 Regel 6c: keine Exception-Spezifikation

Spec: §7.11.1.1.2, S. 61 — “c. The functions shall not have any exception specification even if the IDL operation has an exception specification.”

Repo: crates/lang-rules/src/emit/interface_cpp.rs::sync_method (is_noexcept: false, kein throw(...)); Commit ad892a10764a.

Tests: crates/lang-rules/tests/interface_bindings.rs::cpp_declares_the_synchronous_operations_of_rule_six

Status: done

§7.11.1.1.2 Regel 6d: einfache Typen und Container nach DDS-Cxx-PSM §7.4.2

Spec: §7.11.1.1.2, S. 61 — “d. The mapping of IDL primitive and container types to C++ types is provided in sub clause 7.4.2 in [DDS-Cxx-PSM].”

Repo: crates/lang-rules/src/adapter/cpp.rs::cpp_value_type und crates/lang-rules/src/adapter/cpp_psm.rs::psm_type, aufgerufen aus crates/lang-rules/src/emit/interface_cpp.rs::user_type und sync_method; Commits ad892a10764a, 93962a6aac1c, fb51779ae3bc.

Tests: crates/lang-rules/tests/interface_bindings.rs::cpp_declares_the_synchronous_operations_of_rule_six, crates/lang-rules/tests/interface_cpp_psm_types.rs::the_interface_spells_the_types_of_table_7_1, crates/lang-rules/tests/interface_cpp_psm_types.rs::the_bodies_convert_between_the_psm_types_and_the_topic_structures, crates/rpc/tests/cpp_function_call.rs::the_generated_client_calls_the_generated_service, crates/rpc/tests/cpp_enhanced_function_call.rs::the_generated_enhanced_client_calls_the_generated_enhanced_service

Status: done — std::wstring, std::map und ::dds::core::array stehen in den Argumenten, Rückgaben und Attributen der synchronen Schnittstelle; das ist die Voreinstellung --cpp-mapping psm, --cpp-mapping native ist eine benannte Einstellung (93962a6aac1c, Test interface_cpp_psm_types.rs::the_interface_spells_the_types_of_table_7_1; die C++-Läufe unter der Voreinstellung: cpp_function_call, cpp_enhanced_function_call).

§7.11.1.1.2 Regel 6e: Übergabe nach DDS-Cxx-PSM §7.4.5

Spec: §7.11.1.1.2, S. 61 — “e. The mapping of In, Out, and InOut primitive and constructed types (e.g., struct) is provided in sub clause 7.4.5 in [DDS-Cxx-PSM].”

Repo: crates/lang-rules/src/emit/interface_cpp.rs (passed, is_native); Commit ad892a10764a.

Tests: crates/lang-rules/tests/interface_bindings.rs::cpp_declares_the_synchronous_operations_of_rule_six

Status: done

§7.11.1.1.2 Regel 6f: Getter und Setter nach DDS-Cxx-PSM §7.4.6

Spec: §7.11.1.1.2, S. 61 — “f. Getter/Setter functions for attributes in an interface is specified in sub clause 7.4.6 in [DDS-Cxx-PSM].”

Repo: crates/lang-rules/src/emit/interface_cpp.rs::attribute_method; Commit ad892a10764a.

Tests: crates/lang-rules/tests/interface_bindings.rs::cpp_names_an_attribute_accessor_after_the_attribute

Status: done

§7.11.1.1.2 Regel 6g: einfache Typen und Aufzählungen als Wert

Spec: §7.11.1.1.2, S. 61 — “g. IDL operations that return primitive types and enumeration types the corresponding C++ function shall return the C++ type by value”.

Repo: crates/lang-rules/src/emit/interface_cpp.rs::sync_method (is_native); Commit ad892a10764a.

Tests: crates/lang-rules/tests/interface_bindings.rs::cpp_declares_the_synchronous_operations_of_rule_six

Status: done

§7.11.1.1.2 Regel 6h: konstruierte Rückgabe als cxx_return

Spec: §7.11.1.1.2, S. 61 — “h. IDL operations that return constructed type (e.g., struct) shall map to the first parameter with name “cxx_return” of type a T& to the function and the function shall return void.”

Repo: crates/lang-rules/src/emit/interface_cpp.rs::sync_method; Commit ad892a10764a.

Tests: crates/lang-rules/tests/interface_bindings.rs::cpp_declares_the_synchronous_operations_of_rule_six

Status: done — Zeichenketten und Folgen behandelt ZeroDDS wie konstruierte Typen; die Regeln 6g und 6h nennen sie nicht.

§7.11.1.1.2 Regel 7: rein virtuelle asynchrone Funktionen

Spec: §7.11.1.1.2, S. 62 — “7. The “${interface}Async” abstract class shall contain asynchronous public pure virtual functions for all the operations and attributes defined in the IDL using the following rules”.

Repo: crates/lang-rules/src/emit/interface_cpp.rs (async_interface, async_method, async_attribute_method); Commit ad892a10764a.

Tests: crates/lang-rules/tests/interface_bindings.rs::cpp_declares_the_asynchronous_operations_of_rule_seven

Status: done

§7.11.1.1.2 Regel 7a: Name ${operation}_async

Spec: §7.11.1.1.2, S. 62 — “a. The name of the function shall be “${operation}_async”.”

Repo: crates/lang-rules/src/emit/interface_cpp.rs::async_method; Commit ad892a10764a.

Tests: crates/lang-rules/tests/interface_bindings.rs::cpp_declares_the_asynchronous_operations_of_rule_seven

Status: done

§7.11.1.1.2 Regel 7b: nur In und InOut

Spec: §7.11.1.1.2, S. 62 — “b. The function shall accept only In and InOut parameters and shall have no Out parameters.”

Repo: crates/lang-rules/src/emit/interface_cpp.rs::async_method (operation.inputs()); Commit ad892a10764a.

Tests: crates/lang-rules/tests/interface_bindings.rs::cpp_declares_the_asynchronous_operations_of_rule_seven

Status: done

§7.11.1.1.2 Regel 7c: keine Exception-Spezifikation

Spec: §7.11.1.1.2, S. 62 — “c. The functions shall not have any exception specification even if the IDL operation has an exception specification.”

Repo: crates/lang-rules/src/emit/interface_cpp.rs::async_method; Commit ad892a10764a.

Tests: crates/lang-rules/tests/interface_bindings.rs::cpp_declares_the_asynchronous_operations_of_rule_seven

Status: done

§7.11.1.1.2 Regel 7d: einfache Typen und Container, alle const

Spec: §7.11.1.1.2, S. 62 — “d. The mapping of IDL primitive and container types to C++ types is provided in sub clause 7.4.2 in [DDS-Cxx-PSM]. All the arguments shall be const.”

Repo: crates/lang-rules/src/emit/interface_cpp.rs::async_method (Argumente über user_type); Commits ad892a10764a, 93962a6aac1c.

Tests: crates/lang-rules/tests/interface_bindings.rs::cpp_declares_the_asynchronous_operations_of_rule_seven, crates/lang-rules/tests/interface_cpp_psm_types.rs::the_enhanced_futures_hold_the_applications_types, crates/lang-rules/tests/interface_cpp_psm_types.rs::the_futures_hold_the_applications_types

Status: done — alle Argumente sind const, mit den Typen von Table 7.1 in der Voreinstellung --cpp-mapping psm, und future<…> hält die Typen der Anwendung (576747fa1310, 1240c62e4ec6; Tests interface_cpp_psm_types.rs::the_futures_hold_the_applications_types und ::the_enhanced_futures_hold_the_applications_types).

§7.11.1.1.2 Regel 7e: In und InOut nach §7.4.5, alle const

Spec: §7.11.1.1.2, S. 62 — “e. The mapping of In and InOut primitive and constructed types (e.g.,struct) is provided in sub clause 7.4.5 in [DDs-Cxx-PSM]. All the arguments shall be const.”

Repo: crates/lang-rules/src/emit/interface_cpp.rs::async_method; Commit ad892a10764a.

Tests: crates/lang-rules/tests/interface_bindings.rs::cpp_declares_the_asynchronous_operations_of_rule_seven

Status: done

§7.11.1.1.2 Regel 7f: Getter liefert future des Attributtyps

Spec: §7.11.1.1.2, S. 62 — “f. Attribute getter functions shall take no parameters and shall return dds::rpc::future of the same type as the attribute.”

Repo: crates/lang-rules/src/emit/interface_cpp.rs (async_interface, async_attribute_method); Commit ad892a10764a.

Tests: crates/lang-rules/tests/interface_bindings.rs::cpp_names_an_attribute_accessor_after_the_attribute

Status: done

§7.11.1.1.2 Regel 7g: Setter liefert future

Spec: §7.11.1.1.2, S. 62 — “g. Attribute setter functions shall take a parameter as per specified in sub clause 7.4.6 in [DDS-Cxx-PSM]. It shall return a dds::rpc::future.”

Repo: crates/lang-rules/src/emit/interface_cpp.rs (async_interface, async_attribute_method); Commit ad892a10764a.

Tests: crates/lang-rules/tests/interface_bindings.rs::cpp_names_an_attribute_accessor_after_the_attribute

Status: done

§7.11.1.1.2 Regel 7h: Rückgabe als future des Typs

Spec: §7.11.1.1.2, S. 62 — “h. Operation that produce a return value in the form of a regular return (primitive or constructed type) shall return a value of dds::rpc::future of that type.”

Repo: crates/lang-rules/src/emit/interface_cpp.rs::async_method; Commit ad892a10764a.

Tests: crates/lang-rules/tests/interface_bindings.rs::cpp_declares_the_asynchronous_operations_of_rule_seven

Status: done

§7.11.1.1.2 Regel 7i: future der Out-Struktur oder future

Spec: §7.11.1.1.2, S. 62 — “i. Operation that produces return values with one or more Out/InOut parameters shall return a value of dds::rpc::future of “${interface}_${operation}_Out” type. Otherwise, it will return dds::rpc::future.”

Repo: crates/lang-rules/src/emit/interface_cpp.rs::async_method (async_payload, has_outputs); Commit ad892a10764a.

Tests: crates/lang-rules/tests/interface_bindings.rs::cpp_declares_the_asynchronous_operations_of_rule_seven

Status: done

§7.11.1.1.2 — Abweichungen von Table 7.1

Spec: §7.11.1.1.2, S. 61–62 — Regeln 6d und 7d; DDS-Cxx-PSM §7.4.2, Table 7.1: “string std::wstring”, “map<K, V> std::map<K, V>”, “T[N] dds::core::array<T, N>”.

Repo: crates/lang-rules/src/emit/interface_cpp.rs (user_type, converted, async_payload), crates/lang-rules/src/adapter/cpp_psm.rs::psm_type, crates/cpp/include/zerodds/psm/convert.hpp (zerodds::psm::Conv); Commits 1db807cbf0fb, 93962a6aac1c, fb51779ae3bc.

Tests: crates/lang-rules/tests/interface_cpp_psm_types.rs::the_interface_spells_the_types_of_table_7_1, crates/lang-rules/tests/interface_cpp_psm_types.rs::the_native_mapping_keeps_the_native_spelling, crates/lang-rules/tests/interface_cpp_psm_types.rs::the_bodies_convert_between_the_psm_types_and_the_topic_structures, crates/lang-rules/tests/interface_cpp_psm_types.rs::the_header_compiles, crates/lang-rules/tests/interface_cpp_psm_types.rs::the_enhanced_futures_hold_the_applications_types

Status: done — In der Voreinstellung --cpp-mapping psm schreiben abstrakte Schnittstelle, Client und Dienst die Zeilen von Table 7.1 (std::wstring, std::map, ::dds::core::array) und wandeln in den Rümpfen mit zerodds::psm::Conv in die Topic-Typen. Die Futures der _async-Funktionen und der Attribut-Zugriffe halten die Typen der Anwendung, die Out-Struktur ist die der Anwendung, in der Basic-Abbildung (576747fa1310, 9ee81a26e23b) und in der Enhanced-Abbildung (1240c62e4ec6, Test interface_cpp_psm_types.rs::the_enhanced_futures_hold_the_applications_types; der Linux-Testhost übersetzt beide Fassungen in the_header_compiles). --cpp-mapping native schreibt die nativen Typen und ist eine benannte Einstellung.

§7.11.1.1.2 Regel 8: Präfix cxx_ für reservierte Wörter

Spec: §7.11.1.1.2, S. 62 — “8. Any identifier (e.g., parameter, operation name, exception, interface, module) in an IDL file that is a reserved word in C++ shall be prefixed by “cxx_”.”

Repo: crates/lang-rules/src/emit/interface_cpp.rs::cxx_escape (ruft crates/lang-rules/src/adapter/cpp.rs::cxx_name); Commits ad892a10764a (Interface, Operation, Parameter), 688eb96e852a (Exception), cdb7355e3744 (Module, Typen).

Tests: crates/lang-rules/tests/interface_bindings.rs::cpp_prefixes_a_reserved_word_with_cxx, crates/lang-rules/tests/interface_bindings.rs::cpp_names_a_reserved_exception_with_the_cxx_prefix, crates/lang-rules/tests/interface_bindings.rs::cpp_names_a_reserved_module_and_type_with_the_cxx_prefix

Status: done — Interface, Operation, Parameter, Exception, Modul, deklarierter Typ, Mitglieder, Aufzählungswerte und Konstanten erhalten cxx_ (Item „Mitglieder, Aufzählungswerte und Konstanten“ unten, Commit d750a045b9fe).

§7.11.1.1.2 Regel 8 — Mitglieder, Aufzählungswerte und Konstanten

Spec: §7.11.1.1.2, S. 62 — wie oben.

Repo: crates/lang-rules/src/adapter/cpp.rs::cxx_name, aufgerufen für Mitglieder (Struktur, Union, Exception, Bitset), Aufzählungswerte und Konstanten; Commit d750a045b9fe.

Tests: crates/lang-rules/tests/cxx_prefix_members.rs::a_member_that_is_a_reserved_word_is_prefixed_by_cxx, crates/lang-rules/tests/cxx_prefix_members.rs::an_enumerator_and_a_constant_that_are_reserved_words_are_prefixed_by_cxx, crates/lang-rules/tests/cxx_prefix_members.rs::the_codec_refers_to_the_prefixed_member, crates/lang-rules/tests/cxx_prefix_members.rs::the_idl_names_table_maps_the_prefixed_name_back_to_the_idl_spelling

Status: done — long static; wird std::int32_t cxx_static;; Aufzählungswerte und Konstanten erhalten cxx_. Codec und die Tabellen _idl_names verwenden den Namen mit Präfix und führen die IDL-Schreibweise zurück.

§7.11.1.2 Enhanced: Request/Reply

Spec: §7.11.1.2, S. 62 — “The request-reply style language binding for the Enhanced Service Mapping shall use either the user-defined IDL structs directly or the structs synthesized from an IDL interface. The IDL shall be mapped to C++ types as defined in [DDS-Cxx-PSM].”

Repo: runtime/cpp/include/dds/rpc.hpp (Requester<TReq, TRep>, Replier<TReq, TRep>); crates/lang-rules/src/emit/interface_cpp/enhanced.rs; Commits 45ead22cc2b9, 2ea2abb7d843.

Tests: crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together, crates/rpc/tests/cpp_enhanced_function_call.rs::the_generated_enhanced_client_calls_the_generated_enhanced_service, crates/lang-rules/tests/enhanced_cpp_calls.rs::the_enhanced_header_compiles

Status: done — die Templates nehmen die Strukturen der Enhanced-Abbildung (enhanced.rs erzeugt sie, Correlation::SAMPLE_IDENTITY). Die Abbildung der IDL-Typen auf C++ folgt DDS-Cxx-PSM Table 7.1 in der Voreinstellung --cpp-mapping psm (Item „§7.11.1.1.2 — Abweichungen von Table 7.1“).

§7.11.1.2 Enhanced: Function-call nach §7.11.1.1.2

Spec: §7.11.1.2, S. 62 — “The function-call style language binding for the Enhanced Service Mapping shall use the mapping rules defined in 7.11.1.1.2 Function-Call Style Language Binding.”

Repo: crates/lang-rules/src/emit/interface_cpp.rs (sync_interface, async_interface), crates/lang-rules/src/emit/interface_cpp/calls.rs; Commit 45ead22cc2b9.

Tests: crates/lang-rules/tests/enhanced_cpp_calls.rs::the_function_call_classes_are_written_over_the_choice_structures, crates/lang-rules/tests/enhanced_cpp_calls.rs::a_derived_interface_answers_the_inherited_operation_itself, crates/rpc/tests/cpp_enhanced_function_call.rs::the_generated_enhanced_client_calls_the_generated_enhanced_service, crates/lang-rules/tests/interface_cpp_psm_types.rs::the_enhanced_futures_hold_the_applications_types

Status: done — abstrakte Klassen, Client und Dienst gibt es für die Enhanced-Abbildung. Die Regeln 6d und 7d gelten wie in der Basic-Abbildung: Table 7.1 in der Voreinstellung --cpp-mapping psm, und future<…> hält die Typen der Anwendung (1240c62e4ec6, Test interface_cpp_psm_types.rs::the_enhanced_futures_hold_the_applications_types).

§7.11.1.3 Lokale Exceptions nach DDS-Cxx-PSM §7.5.5

Spec: §7.11.1.3, S. 62 — “The C++ language binding may throw locally generated and remotely generated exceptions. As such, all DDS exceptions defined in sub clause 7.5.5 in [DDS-Cxx-PSM] are valid exceptions.”

Repo: runtime/cpp/include/dds/rpc.hpp (LocalError und zehn abgeleitete Klassen: NullReferenceError, AlreadyClosedError, IllegalOperationError, PreconditionNotMetError, OutOfResourcesError, TimeoutError, ImmutablePolicyError, InconsistentPolicyError, UnsupportedError, InvalidArgumentError); Commit 2ea2abb7d843.

Tests: crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together

Status: done — lokale Fehler werfen diese Klassen in dds::rpc, benannt nach den Klassen aus DDS-Cxx-PSM §7.5.5 (2ea2abb7d843). Liegt crates/cpp/include auf dem Pfad (ZERODDS_RPC_HAS_DDS_CORE_EXCEPTION), erbt jede Klasse von der gleichnamigen Klasse in dds::core (über die virtuelle Basis dds::core::Exception; crates/cpp/include/dds/core/Exception.hpp erbt dazu virtuell): ein catch (const dds::core::TimeoutError&) fängt dds::rpc::TimeoutError, ebenso catch (const dds::core::Exception&) (edb565cfcd88). Ein Status der C-API ohne zugeordnete Klasse wirft UnspecifiedError. Test: static_asserts und catch-Fälle in crates/rpc/tests/cpp/rpc_runtime_roundtrip.cpp, gefahren von crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together (Linux-Testhost, grün). Ohne crates/cpp/include auf dem Pfad gibt es die Klassen von DDS-Cxx-PSM nicht, und die Basis ist std::runtime_error.

§7.11.1.3 Tabelle: Codes auf Exceptions

Spec: §7.11.1.3, S. 63 — “REMOTE_EX_OK No exception; REMOTE_EX_UNSUPPORTED dds::rpc::RemoteUnsupportedError; REMOTE_EX_INVALID_ARGUMENT dds::rpc::RemoteInvalidArgumentError; REMOTE_EX_OUT_OF_RESOURCES dds::rpc::RemoteOutOfResourcesError; REMOTE_EX_UNKNOWN_OPERATION dds::rpc::RemoteUnknownOperationError; REMOTE_EX_UNKNOWN_EXCEPTION dds::rpc::RemoteUnknownExceptionError”.

Repo: runtime/cpp/include/dds/rpc/base.hpp::raise_remote_exception; crates/rpc/src/language_binding.rs::cpp_exception_class; Commits ad892a10764a, 2fe2b7cdea14 (sechs Codes).

Tests: crates/rpc/src/language_binding.rs::tests::the_table_of_seven_eleven_one_three_is_the_published_one, crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together

Status: done

§7.11.1.3 Figure 7.6 — Vererbung der Exceptions

Spec: §7.11.1.3, S. 63, Figure 7.6 — RemoteOutOfResourcesError unter std::runtime_error; RemoteUnsupportedError, RemoteUnknownOperationError, RemoteUnknownExceptionError unter std::logic_error; RemoteInvalidArgumentError unter std::invalid_argument; die Klassen der rechten Spalte zusätzlich unter dds::core::Exception.

Repo: runtime/cpp/include/dds/rpc.hpp (RemoteOutOfResourcesError, RemoteUnsupportedError, RemoteInvalidArgumentError, RemoteUnknownOperationError, RemoteUnknownExceptionError, detail::ExceptionRoot); Commits ad892a10764a, f8116b6debc1.

Tests: crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together

Status: done — die Basen aus std:: stimmen; alle fünf Klassen erben zusätzlich von detail::ExceptionRoot, das mit dds/core/Exception.hpp auf dem Include-Pfad dds::core::Exception ist (static_assert(std::is_base_of<…>) in check_exception_hierarchy von rpc_runtime_roundtrip.cpp; cpp_rpc_runtime.rs übergibt crates/cpp/include).

§7.11.1.3 Basis dds::core::Exception

Spec: §7.11.1.3, S. 63, Figure 7.6 — wie oben.

Repo: runtime/cpp/include/dds/rpc.hpp (detail::ExceptionRoot, ZERODDS_RPC_HAS_DDS_CORE_EXCEPTION, LocalError); crates/cpp/include/dds/core/Exception.hpp; Commit f8116b6debc1.

Tests: crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together

Status: done — rpc.hpp bindet dds/core/Exception.hpp ein, wenn __has_include sie findet; dann ist detail::ExceptionRoot gleich dds::core::Exception. Ohne die PSM-Header steht dort eine Klasse gleicher Form (what()). check_exception_hierarchy prüft die fünf Remote*Error und LocalError mit static_assert.

§7.11.1.4.1 Namespaces dds und dds::rpc mit 22 Klassen

Spec: §7.11.1.4.1, S. 64 — “The dds, and dds::rpc namespaces define the classes and functions for the request-reply style language bindings. Specifically, the language binding includes RPCEntity, Requester, Replier, ServiceProxy, ListenerBase, SimpleReplierListener, ReplierListener, SimpleRequesterListener, RequesterListener, RequesterParams, ReplierParams, future, shared_future, Sample, SampleRef, WriteSample, WriteSampleRef, LoanedSamples, SharedSamples, SampleIterator, dds_type_traits, and dds_entity_traits.”

Repo: runtime/cpp/include/dds/rpc.hpp; crates/rpc/src/language_binding.rs (CPP_NAMESPACES, CPP_REQUEST_REPLY_CLASSES); Commits ad892a10764a, 2ea2abb7d843.

Tests: crates/rpc/tests/class_summaries_are_declared.rs::the_cpp_runtime_declares_every_class_of_the_two_summaries

Status: done

§7.11.1.4.1 Bindung unabhängig vom Profil

Spec: §7.11.1.4.1, S. 64 — “C++ request-reply language binding uses templates. […] Depending upon the profile in use (Basic/Enhanced), the actual structure of the TReq and TRep types will vary. However, the request-reply language binding is independent of the profile in use.”

Repo: runtime/cpp/include/dds/rpc.hpp (Requester<TReq, TRep>, Replier<TReq, TRep>, Correlation); Commits ad892a10764a, 45ead22cc2b9.

Tests: crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together, crates/rpc/tests/cpp_enhanced_function_call.rs::the_generated_enhanced_client_calls_the_generated_enhanced_service

Status: done — dieselben Templates tragen die Strukturen der Basic-Abbildung (Correlation::HEADER) und der Enhanced-Abbildung (Correlation::SAMPLE_IDENTITY).

§7.11.1.4.2 RPCEntity mit close() und is_null()

Spec: §7.11.1.4.2, S. 64 — “RPCEntity is the base abstract class extended by all the active RPC entities. It supports close() and is_null() operations.”

Repo: runtime/cpp/include/dds/rpc/base.hpp::RPCEntity (abgeleitet: ServiceProxy, ServiceEndpoint, Server); Commits ad892a10764a, f8116b6debc1.

Tests: crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together

Status: done — close() und is_null() sind rein virtuell in RPCEntity; Requester, Replier, ServiceEndpoint und Server erben davon (static_assert(std::is_base_of<dds::rpc::RPCEntity, …>) in rpc_runtime_roundtrip.cpp).

§7.11.1.4.3 Requester sendet Requests und empfängt Replies

Spec: §7.11.1.4.3, S. 64 — “A requester sends requests and receives replies.”

Repo: runtime/cpp/include/dds/rpc.hpp::Requester; Commit ad892a10764a.

Tests: crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together

Status: done

§7.11.1.4.3 Requester ist Referenztyp

Spec: §7.11.1.4.3, S. 64 — “Requester is a reference type and when copied it makes a shallow copy.”

Repo: runtime/cpp/include/dds/rpc.hpp::Requester (std::shared_ptr<Impl>, ServiceProxy::Binding); Commit 2ea2abb7d843.

Tests: crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together

Status: done — eine Kopie teilt Impl (Writer, Reader, Antworten, offene future) und die Bindung an die Instanz; close() an der Kopie schließt für alle.

§7.11.1.4.3 Konfiguration über RequesterParams

Spec: §7.11.1.4.3, S. 64 — “An instance of a Requester is configured at the time of construction using RequesterParams, which is a container of configuration parameters, such as domain participant, QoS, listeners and more.”

Repo: runtime/cpp/include/dds/rpc.hpp (EndpointParams, RequesterParams, Requester(const RequesterParams&)); Commits 2ea2abb7d843, 7253f8222589 (QoS), 05c799d7e041 (Listener).

Tests: crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together, crates/rpc/tests/cpp_rpc_zerodds_qos.rs::the_zerodds_binding_carries_the_rpc_qos_to_the_c_api

Status: done — RequesterParams trägt Participant, Publisher, Subscriber, Namen der Topics, Namen des Dienstes und der Instanz, RpcQos oder Profil-URLs und einen Listener.

§7.11.1.4.3 Empfang über Listener, Abfrage und future

Spec: §7.11.1.4.3, S. 64 — “Requester allows listener-based, polling-based, and future-based reception of replies. […] Future-based notification of replies is analogous to callback-based notification, however, no request-reply correlation is necessary because every future represents a reply to a unique request.”

Repo: runtime/cpp/include/dds/rpc.hpp (Requester::receive_replies, receive_reply, send_request_async, dispatch_replies, Konstruktor mit impl_->listen); Commits ad892a10764a, 05c799d7e041 (Listener und future bei Ankunft).

Tests: crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together, crates/rpc/tests/cpp_rpc_zerodds_listener.rs::the_zerodds_reader_calls_its_callback_on_arrival_and_not_after_removal

Status: done

§7.11.1.4.3 Gebundener Requester erreicht nur seine Instanz

Spec: §7.11.1.4.3, S. 64 — “A requester reference may be bound to a specific service instance. Requests sent through a bound requester reference shall be sent to the bound service instance only.”

Repo: runtime/cpp/include/dds/rpc.hpp (ServiceProxy::bind, Requester::Impl::send_locked setzt RequestHeader::instance_name, Replier::Impl::receive_requests filtert); crates/rpc/src/replier.rs::Replier::tick; Commits 35aa702e4900 (Filter), 2ea2abb7d843 (Bindung geteilt).

Tests: crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together, crates/rpc/src/replier.rs::tests::tick_filters_requests_for_other_instance_name, crates/rpc/src/replier.rs::tests::a_named_replier_does_not_answer_a_request_without_an_instance, crates/rpc/tests/runtime_e2e.rs::e2e_instance_routing_filters_per_replier

Status: done — Basic-Profil: Der Request trägt den Namen der Instanz im Header; ein Replier mit ungleichem Namen verwirft ihn (strenge Gleichheit, der leere Name passt nur auf den leeren Namen), auch auf dem Weg über dispatch_requests. Enhanced-Profil: Item unten.

§7.11.1.4.3 Bindung an die Instanz im Enhanced-Profil

Spec: §7.11.1.4.3, S. 64 — wie oben.

Repo: runtime/cpp/include/dds/rpc.hpp (Requester::Impl::send_locked, readers_of_instance, DataWriter::write_to); runtime/cpp/include/dds/rpc/zerodds.hpp::write_to; crates/zerodds-c-api (zerodds_writer_write_to_readers, zerodds_writer_next_sequence_number); crates/dcps (DcpsRuntime::write_user_sample_to_readers); crates/rtps (CacheChange::destination_readers); Commits 6289b73b7853, 94181922bf32, 95c934ae90bc.

Tests: crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together, crates/zerodds-c-api/tests/write_to_readers.rs::a_sample_written_to_one_reader_reaches_that_reader_only, crates/rtps/src/reliable_writer.rs::tests::a_change_for_one_reader_reaches_the_other_readers_of_its_participant_as_a_gap

Status: done — der Request der Enhanced-Abbildung trägt keinen Namen; Requester::Impl::send_locked schreibt mit write_to nur an die Reader, die den Namen der Instanz angekündigt haben. Die anderen Reader desselben Participants erhalten die Änderung als Gap. check_instance_addressing in rpc_runtime_roundtrip.cpp prüft zwei benannte Replier und den unbenannten (Schleife im Speicher); write_to_readers.rs prüft die Zustellung über die C-API. Grenze: Eine TRANSIENT_LOCAL-Aufbewahrung kennt die Adressaten nicht; das RPC-QoS ist VOLATILE (§7.10.2). Ein ungebundener Enhanced-Request im Discovery-Modus geht nur an Reader ohne Namen. Ohne Discovery der Erweiterung lehnt der Requester einen gebundenen Request mit UnsupportedError ab (aus dem Code gelesen).

§7.11.1.4.4 ServiceProxy

Spec: §7.11.1.4.4, S. 64 — “ServiceProxy class defines type-independent operations for Requester and the Client. For example, binding to a specific instance, waiting for an instance to discover, closing the service, and more. ServiceProxy shall not be instantiated directly.”

Repo: runtime/cpp/include/dds/rpc.hpp::ServiceProxy (bind, unbind, wait_for_service, geschützter Konstruktor); Commits ad892a10764a, 2ea2abb7d843.

Tests: crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together

Status: done — wait_for_service() prüft, ob der Dienst entdeckt ist; die Überladung mit Zeitspanne wartet bis dahin.

§7.11.1.4.5 Replier

Spec: §7.11.1.4.5, S. 64 — “A replier receives requests and send replies. Replier is a reference type and it is inexpensive to copy […] An instance of Replier is configured at the time of construction using ReplierParams, which is a container of configuration parameters such as domain participant, QoS, listeners and more. Replier allows listener-based and polling-based reception of requests.”

Repo: runtime/cpp/include/dds/rpc.hpp::Replier (std::shared_ptr<Impl>, receive_requests, send_reply, dispatch_requests, set_qos); Commits ad892a10764a, 2ea2abb7d843, 7253f8222589, 05c799d7e041.

Tests: crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together, crates/rpc/tests/cpp_rpc_zerodds_listener.rs::the_zerodds_reader_calls_its_callback_on_arrival_and_not_after_removal

Status: done — Referenztyp mit geteiltem Impl; ReplierParams trägt Participant, QoS und Listener; Empfang über Listener (bei Ankunft) und Abfrage.

§7.11.1.4.6 ListenerBase

Spec: §7.11.1.4.6, S. 65 — “ListenerBase is a “marker” abstract base class, which all generic listener abstract classes inherit from. It defines no member functions.”

Repo: runtime/cpp/include/dds/rpc/base.hpp::ListenerBase (nur der virtuelle Destruktor); Commit ad892a10764a.

Tests: crates/rpc/tests/class_summaries_are_declared.rs::the_cpp_runtime_declares_every_class_of_the_two_summaries

Status: done ### §7.11.1.4.7 SimpleReplierListener

Spec: §7.11.1.4.7, S. 65 — “SimpleReplierListener<TReq, TRep> is used to provide a synchronous request listener for a Replier. ReplierParams is used to pass an instance […] the callback provides the request object and expects the reply as the return value.”

Repo: runtime/cpp/include/dds/rpc/base.hpp::SimpleReplierListener (process_request); Commit ad892a10764a, Aufruf bei Ankunft 05c799d7e041

Tests: crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together

Status: done

§7.11.1.4.8 ReplierListener

Spec: §7.11.1.4.8, S. 65 — “ReplierListener<TReq, TRep> interface is used to provide an asynchronous request listener for a Replier. […] the callback provides the Replier object and returns void.”

Repo: runtime/cpp/include/dds/rpc/base.hpp::ReplierListener (on_request_available(Replier&)); Commit ad892a10764a, Aufruf bei Ankunft 05c799d7e041

Tests: crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together

Status: done

§7.11.1.4.9 SimpleRequesterListener

Spec: §7.11.1.4.9, S. 65 — “SimpleRequesterListener abstract class is used to receive notifications of arrival of replies. […] the callback provides access to the reply sample and returns void.”

Repo: runtime/cpp/include/dds/rpc/base.hpp::SimpleRequesterListener (process_reply); Commit ad892a10764a, Aufruf bei Ankunft 05c799d7e041

Tests: crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together

Status: done

§7.11.1.4.10 RequesterListener

Spec: §7.11.1.4.10, S. 65 — “RequesterListener<TReq,TRep> interface is used to receive notification of reply arrival. […] the callback provides the replier object and returns void.”

Repo: runtime/cpp/include/dds/rpc/base.hpp::RequesterListener (on_reply_available(Requester&)); Commit ad892a10764a, Aufruf bei Ankunft 05c799d7e041

Tests: crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together

Status: done — der Rückruf erhält den Requester; die Spec schreibt „replier object“.

§7.11.1.4.11 RequesterParams

Spec: §7.11.1.4.11, S. 65 — “RequesterParams is a valuetype that serves as a container of configuration parameters of a Requester.”

Repo: runtime/cpp/include/dds/rpc.hpp::RequesterParams; Commit ad892a10764a, Form nach §7.11.1.3 bis §7.11.1.5 2ea2abb7d843, QoS 7253f8222589

Tests: crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together

Status: done

§7.11.1.4.12 ReplierParams

Spec: §7.11.1.4.12, S. 65 — “ReplierParams is a valuetype that serves as a container of configuration parameters of a Replier.”

Repo: runtime/cpp/include/dds/rpc.hpp::ReplierParams; Commit ad892a10764a, Form nach §7.11.1.3 bis §7.11.1.5 2ea2abb7d843, QoS 7253f8222589

Tests: crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together

Status: done

§7.11.1.4.13 future

Spec: §7.11.1.4.13, S. 65 — “In C++11 and C++14 environments, dds::rpc::future is a typedef for std::future. […] Future is not copyable but it is movable.”

Repo: runtime/cpp/include/dds/rpc.hpp (using future = std::future<T>); Commit ad892a10764a

Tests: crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together

Status: done

§7.11.1.4.14 shared_future

Spec: §7.11.1.4.14, S. 65 — “shared_future is closely related to future and the only difference is that shared_future is copyable and movable.”

Repo: runtime/cpp/include/dds/rpc.hpp (using shared_future = std::shared_future<T>); Commit ad892a10764a

Tests: crates/rpc/tests/class_summaries_are_declared.rs::the_cpp_runtime_declares_every_class_of_the_two_summaries

Status: done

§7.11.1.4.15 Sample

Spec: §7.11.1.4.15, S. 65 — “Sample is a valetype that combines a value of type T and a value of type SampleInfo. Sample is conceptually immutable.”

Repo: runtime/cpp/include/dds/rpc.hpp::Sample (nur lesende Zugriffe); Commit ad892a10764a

Tests: crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together

Status: done

§7.11.1.4.16 SampleRef

Spec: §7.11.1.4.16, S. 65 — “SampleRef is a reference type that combines a value of type T and a value of type SampleInfo. Copying SampleRef makes a shall copy.”

Repo: runtime/cpp/include/dds/rpc/base.hpp::SampleRef (über std::shared_ptr<Sample<T>>); Commit ad892a10764a

Tests: crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together

Status: done

§7.11.1.4.17 WriteSample

Spec: §7.11.1.4.17, S. 66 — “WriteSample is a valuetype that combines a value of type T and a value of type dds::SampleIdentity. The user populates the value of T and the middleware populates the value of dds::SampleIdentity. When a request is sent as a WriteSample, upon function return, the WriteSample.identity()uniquely identifies the request sent.”

Repo: runtime/cpp/include/dds/rpc.hpp (WriteSample; Requester::send_request(WriteSample<TReq>&)); Commit ad892a10764a

Tests: crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together

Status: done

§7.11.1.4.18 WriteSampleRef

Spec: §7.11.1.4.18, S. 66 — “WriteSampleRef is a reference type, which groups a reference to T and a value of type dds::SampleIdentity. […] When a request is sent as a WriteSampleRef, upon function return, the WriteSample.identity()uniquely identifies the request sent.”

Repo: runtime/cpp/include/dds/rpc/base.hpp::WriteSampleRef (über std::shared_ptr<WriteSample<T>>); Commit ad892a10764a

Tests: crates/rpc/tests/class_summaries_are_declared.rs::the_cpp_runtime_declares_every_class_of_the_two_summaries, crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together

Status: done — das Senden als WriteSampleRef steht im Item unten.

§7.11.1.4.18 Senden als WriteSampleRef

Spec: §7.11.1.4.18, S. 66 — wie oben.

Repo: runtime/cpp/include/dds/rpc/core.hpp::Requester::send_request(WriteSampleRef<TReq>); Commit 2ea2abb7d843

Tests: crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together (Programm crates/rpc/tests/cpp/rpc_runtime_roundtrip.cpp: die Identität steht nach dem Senden im Sample, auf das die Referenz zeigt)

Status: done

§7.11.1.4.19 LoanedSamples

Spec: §7.11.1.4.19, S. 66 — “LoanedSamples is conceptually a container of loaned Sample from the middleware. LoanedSamples is not copyable but it is movable. LoanedSamples::value_type is SampleRef. Upon destruction, LoanedSamples returns the loaned samples to the middleware.”

Repo: runtime/cpp/include/dds/rpc/base.hpp::LoanedSamples (Kopieren gelöscht, Verschieben erlaubt); Commit ad892a10764a

Tests: crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together

Status: done — die Samples sind Kopien; zurückzugeben ist nichts.

§7.11.1.4.20 SharedSamples

Spec: §7.11.1.4.20, S. 66 — “All copies of a SharedSamples refer to the same set of loaned samples. SharedSamples::value_type is SampleRef. […] Note that SharedSamples can be obtained from LoanedSample but not vice versa.”

Repo: runtime/cpp/include/dds/rpc.hpp (SharedSamples; LoanedSamples::to_shared); Commit ad892a10764a

Tests: crates/rpc/tests/class_summaries_are_declared.rs::the_cpp_runtime_declares_every_class_of_the_two_summaries

Status: done

§7.11.1.4.21 SampleIterator

Spec: §7.11.1.4.21, S. 66 — “SampleIterator is a random-access iterator over LoanedSamples and SharedSamples. SampleIterator::value_type is a SampleRef.”

Repo: runtime/cpp/include/dds/rpc/base.hpp::SampleIterator (std::random_access_iterator_tag); Commit ad892a10764a

Tests: crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together

Status: done

§7.11.1.4.22 dds_type_traits

Spec: §7.11.1.4.22, S. 66 — “dds_type_traits is a collection of meta-functions that given a type T, provides commonly needed dependent types, such as a DataReader for T, DataWriter for T, Sample, LoanedSamples, etc.”

Repo: runtime/cpp/include/dds/rpc/base.hpp::dds_type_traits_base (Seq, ConstSeq, DataReader, DataWriter, SampleRefType, LoanedSamplesType, SharedSamplesType, iterator, const_iterator); dds_type_traits<T> leitet von dds_type_traits_base<T> ab, die erzeugten Spezialisierungen ebenfalls (crates/lang-rules/src/emit/type_pair_cpp.rs, crates/lang-rules/src/emit/interface_cpp/codec.rs, crates/lang-rules/src/emit/interface_cpp/enhanced_codec.rs); Commit f8116b6debc1

Tests: crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together (static_assert in crates/rpc/tests/cpp/rpc_runtime_roundtrip.cpp auf Seq, DataReader, LoanedSamplesType, SharedSamplesType, iterator, const_iterator)

Status: done — DataReader und DataWriter sind die byteorientierten Typen der Laufzeit (std::shared_ptr<::dds::rpc::DataReader>), nicht die Typen einer DDS-C++-Bibliothek.

§7.11.1.4.23 dds_entity_traits

Spec: §7.11.1.4.23, S. 66 — “dds_entity_traits abstracts over the DDS entity types and provides consistent syntax to get DDS entity types irrespective of the DDS C++ language bindings. (e.g., DomainParticipant, Publisher, Subscriber, DataReaderQos, and DataWriterQos).”

Repo: runtime/cpp/include/dds/rpc/base.hpp::dds_entity_traits (DomainParticipant, Publisher, Subscriber, DataWriter, DataReader, DataWriterQos, DataReaderQos); Commit ad892a10764a, Publisher, Subscriber und QoS-Typen 2ea2abb7d843

Tests: crates/rpc/tests/class_summaries_are_declared.rs::the_cpp_runtime_declares_every_class_of_the_two_summaries, crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together (static_assert in crates/rpc/tests/cpp/rpc_runtime_roundtrip.cpp auf DataWriterQos, Publisher, Subscriber)

Status: done

§7.11.1.4.23 dds_entity_traits: Publisher, Subscriber und QoS-Typen

Spec: §7.11.1.4.23, S. 66 — wie oben.

Repo: runtime/cpp/include/dds/rpc/base.hpp::dds_entity_traits; Commit 2ea2abb7d843

Tests: crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together

Status: done — Publisher und Subscriber sind benannt, DataWriterQos und DataReaderQos sind EndpointQos.

§7.11.1.5 Klassen des Stils Function-call

Spec: §7.11.1.5, S. 66 — “Service, ServiceEndpoint, Server, Client, and ClientEndpoint classes are specific to the function-call style language binding and are described below.”

Repo: runtime/cpp/include/dds/rpc.hpp; crates/rpc/src/language_binding.rs::CPP_FUNCTION_CALL_CLASSES; Commit ad892a10764a

Tests: crates/rpc/tests/class_summaries_are_declared.rs::the_cpp_runtime_declares_every_class_of_the_two_summaries

Status: done

§7.11.1.5.1 Service

Spec: §7.11.1.5.1, S. 66 — “Service is a reference type and accepts a reference to the service implementation. A Service instantiates the underlying DDS entities and makes the service discoverable. Every Service inherits from ServiceEndpoint. A Service may belong to only one Server.”

Repo: runtime/cpp/include/dds/rpc.hpp::Service (claim, release_claim); crates/lang-rules/src/emit/interface_cpp/calls.rs::service_class (<I>Service leitet von dds::rpc::Service ab, nimmt <I>& und ServiceParams, legt den Replier an); Commit ec3707125a9b, Zugehörigkeit zu einem Server f8116b6debc1

Tests: crates/lang-rules/tests/interface_bindings.rs::cpp_binds_the_function_call_entities_of_seven_eleven_one_five, crates/rpc/tests/cpp_function_call.rs::the_generated_client_calls_the_generated_service (Programm crates/rpc/tests/cpp/function_call_roundtrip.cpp: ein Service, den ein Server hält, wird von einem zweiten Server und vom selben Server ein zweites Mal mit IllegalOperationError abgewiesen)

Status: done — Referenztyp (Kopien teilen die Entitäten), Referenz auf die Implementierung, Entitäten und Basis ServiceEndpoint stimmen; Server::add weist einen Service ab, der schon einem Server gehört.

§7.11.1.5.2 ServiceEndpoint

Spec: §7.11.1.5.2, S. 67 — “A ServiceEndpoint provides type-independent functions to manage a service (e.g., pause, resume, close, etc.) A ServiceEndpoint shall not be instantiated directly; it can be obtained from a Service object. ServiceEndpoint is a reference type.”

Repo: runtime/cpp/include/dds/rpc.hpp::ServiceEndpoint (pause, resume, close, set_qos, geschützter Konstruktor, Zustand über std::shared_ptr); Commit ad892a10764a

Tests: crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together

Status: done

§7.11.1.5.3 Server

Spec: §7.11.1.5.3, S. 67 — “A Server is a container of one or more Services. Server.run() function begins dispatching the requests to the Service implementation. Server is a reference type.”

Repo: runtime/cpp/include/dds/rpc.hpp::Server (add, run_once, run(), run(until), run(Duration), close, is_null, default_service_params; die Dienste liegen in einem gemeinsamen Zustand, Kopien teilen ihn; Server erbt von RPCEntity); Commit ad892a10764a, Basis, run() und Zugehörigkeit f8116b6debc1

Tests: crates/rpc/tests/cpp_rpc_runtime.rs::the_cpp_rpc_runtime_and_the_generated_header_run_together, crates/rpc/tests/cpp_function_call.rs::the_generated_client_calls_the_generated_service (static_assert(std::is_base_of<dds::rpc::RPCEntity, dds::rpc::Server>) und runner.run() in crates/rpc/tests/cpp/function_call_roundtrip.cpp)

Status: done — Container, Verteilung der Requests, run() ohne Parameter und die Basis RPCEntity stimmen. Der Zustand liegt in einem gemeinsamen Objekt (core::Server), das Kopien teilen; rpc_runtime_roundtrip.cpp kopiert einen Server und lässt die Kopie einen Request beantworten (31b231a9e863), und prüft, dass ein Dienst eines anderen Servers abgewiesen wird. Unter den normativen Headern ist Server das Handle auf core::Server (f2fc6695f1e9).

§7.11.1.5.4 Client

Spec: §7.11.1.5.4, S. 67 — “Client is a reference type and provides functions to invoke operations on a remote service synchronously and asynchronously. A Client instantiates the underlying DDS entities and makes them discoverable. Every Client inherits publicly from “interface”,“{interface}Async”, and ClientEndpoint (public virtual).”

Repo: crates/lang-rules/src/emit/interface_cpp/calls.rs::client_class (<I>Client mit den Basen <I>, <I>Async und public virtual dds::rpc::ClientEndpoint, Operationen über den Requester, Entitäten im Konstruktor); runtime/cpp/include/dds/rpc.hpp::Client; Commit ec3707125a9b

Tests: crates/lang-rules/tests/interface_bindings.rs::cpp_binds_the_function_call_entities_of_seven_eleven_one_five, crates/rpc/tests/cpp_function_call.rs::the_generated_client_calls_the_generated_service

Status: done — Kopien teilen die Entitäten (Programm crates/rpc/tests/cpp/function_call_roundtrip.cpp).

§7.11.1.5.5 ClientEndpoint

Spec: §7.11.1.5.5, S. 67 — “A ClientEndpoint provides functions to obtain the underlying DDS entities at the client side. ClientEndpoint inherits from ServiceProxy. A ClientEndpoint shall not be instantiated directly; it can be obtained from a Client object.”

Repo: runtime/cpp/include/dds/rpc.hpp::ClientEndpoint (get_request_datawriter<TReq>(), get_reply_datareader<TRep>()); Commit ad892a10764a, Zugriff auf die Entitäten f8116b6debc1

Tests: crates/rpc/tests/class_summaries_are_declared.rs::the_cpp_runtime_declares_every_class_of_the_two_summaries, crates/rpc/tests/cpp_function_call.rs::the_generated_client_calls_the_generated_service (Programm crates/rpc/tests/cpp/function_call_roundtrip.cpp: beide Zugriffe liefern Entitäten, der Writer hat mindestens einen Reader)

Status: done — erbt von ServiceProxy, geschützter Konstruktor, close, wait_for_service, set_qos, qos, Zugriff auf Request-DataWriter und Reply-DataReader.

§7.11.1.5 — Service, Server, ClientEndpoint

Spec: §7.11.1.5.1, §7.11.1.5.3, §7.11.1.5.5, S. 66–67 — wie die Items oben.

Repo: runtime/cpp/include/dds/rpc.hpp::Server::add, Server::run, ClientEndpoint::get_request_datawriter; runtime/java/src/main/java/org/omg/dds/rpc/Server.java (run()), runtime/java/src/main/java/org/omg/dds/rpc/ClientEndpoint.java (requestWriter, replyReader); Commits f8116b6debc1 (C++), 17cc6c7ad2a5 (Java)

Tests: crates/rpc/tests/cpp_function_call.rs::the_generated_client_calls_the_generated_service, crates/rpc/tests/java_rpc_runtime.rs::the_java_entities_are_interfaces_and_the_runtime_makes_services_and_clients (Programm crates/rpc/tests/java/RpcInheritanceTest.java: Server hat run(), ClientEndpoint gibt Writer und Reader, ein gebundener Service wird von einem zweiten Server abgewiesen)

Status: done — (1) Server::add (C++) weist einen Service ab, der einem Server gehört (IllegalOperationError); die Java-Bindung tut es mit IllegalStateException. (2) Server hat run() ohne Parameter in C++ und Java. (3) ClientEndpoint gibt in C++ und Java den Request-Writer und den Reply-Reader heraus.

§7.11.2 Maschinenlesbare Dateien für Java

Spec: §7.11.2, S. 67 — “The machine readable files associated with this specification represent the normative language bindings for Java.”

Repo: runtime/java/src/main/java/org/omg/dds/rpc/, crates/rpc/tests/java/omg-dds-rpc-java.signatures (die Deklarationen der Zip-Datei), crates/rpc/tests/java/extract_spec_signatures.py

Tests: crates/rpc/tests/java_rpc_runtime.rs::the_java_binding_has_every_signature_of_the_machine_readable_files (SpecSignatureCheck.java), crates/rpc/tests/java_rpc_runtime.rs::the_java_entities_are_interfaces_and_the_runtime_makes_services_and_clients, crates/rpc/tests/java/RpcRuntimeRoundtrip.java::nondataSamples (…::the_java_rpc_runtime_and_the_generated_services_run_together)

Status: done — omg-dds-rpc-java.zip (von https://www.omg.org/spec/DDS-RPC/20160215/, in internal/standards/cache/omg/, nicht im Repository) ist Deklaration für Deklaration gegen die Laufzeit geprüft: extract_spec_signatures.py schreibt die 212 öffentlichen Deklarationen der Dateien (jeder Typ mit Art, Zahl der Typparameter und Obertypen, jede Methode mit Name, static, Zahl der Typparameter, Parameter- und Rückgabetyp nach Löschung der Typargumente, die Konstruktoren, die Enum-Konstanten) nach omg-dds-rpc-java.signatures, und SpecSignatureCheck.java prüft die übersetzte Laufzeit per Reflexion dagegen. Gemessen auf dem Linux-Testhost: vor der Änderung 76 Abweichungen (011427669d5), danach 0 (d6674336a94). Behoben sind: die Params ohne Typparameter, mit withDataWriterQos, withDataReaderQos, withPublisher, withSubscriber und den Gettern, und die generischen Methoden simpleRequesterListener/requesterListener/simpleReplierListener/replierListener (Item „§7.11.2 Java: Params und DataWriter-Sichten der PSM“); Requester.getRequestDataWriter(), getReplyDataReader(), Replier.getRequestDataReader(), getReplyDataWriter(), ClientEndpoint.getRequestDataWriter(Class), getReplyDataReader(Class), ServiceEndpoint.getRequestDataReader(Class) und getReplyDataWriter(Class) (dasselbe Item); die Parameter vom Typ org.omg.dds.core.SampleIdentity (receiveReply, waitForReplies, takeReply, takeReplies, readReply, readReplies, sendReply); Sample.Iterator ist ein org.omg.dds.sub.Sample.Iterator (§7.11.2.2.7: “the same as in [DDS-Java-PSM]”); die Konstruktoren RequestHeader(), ReplyHeader() und RPCRuntime(); ServiceProxy.waitForService… und waitForServices… geben nichts zurück, warten, und werfen TimeoutError, wenn die Wartezeit abläuft, wie die C++-Bindung (isServiceMatched() fragt ohne zu warten). Die Rückgabetypen sind die der Dateien (f216d90e776): sendRequest gibt org.omg.dds.core.SampleIdentity, sendRequestAsync und die vier waitFor…Async geben java.util.concurrent.Future, die Operationen, die Requests oder Replies empfangen, nehmen oder lesen, geben org.omg.dds.sub.Sample.Iterator; rpc.Sample deklariert keinen eigenen Iterator, wie in der Datei Sample.java. Die Objekte sind die der Laufzeit (org.omg.dds.rpc.SampleIdentity, org.omg.dds.rpc.Future mit dem Completion-Listener, org.zerodds.ddsrpc.RpcSampleIterator mit rpc.Sample-Elementen). Ein Rückgabetyp, der nur ein Untertyp ist, zählt der Test als Abweichung (NARROWER): gegen die Dateien übersetzter Code fände die Methode nicht, weil ihr Deskriptor den Rückgabetyp nennt. Gemessen: vor der Änderung 17 (20241c67565), danach 0. receiveNondataSamples(true) gibt bei Requester und Replier die Samples ohne Daten heraus (valid_data false, DDS 1.4 §2.2.2.5.1) — als Sample mit validData() false, getData() null und dem Zustand der Instanz —, ohne die Einstellung nicht (Vorgabe); der Rückgabewert ist die ersetzte Einstellung. Test: RpcRuntimeRoundtrip.java::nondataSamples über die PSM: ein gelöschter Reply-Writer hinterlässt beim Requester mit der Einstellung ein Sample ohne Daten im Zustand NOT_ALIVE_DISPOSED (die Vorgabe der WRITER_DATA_LIFECYCLE, autodispose TRUE, DDS 1.4 §2.2.3.21), beim Requester ohne sie nichts; ein gelöschter Request-Writer ebenso beim Replier. Vor der Änderung reichte die Bindung solche Samples nicht weiter, beide Prüfungen schlugen fehl (20241c67565). Ein SimpleReplierListener wird für ein Sample ohne Daten nicht gerufen, es bleibt für die nehmenden Operationen. Was die Laufzeit über die Dateien hinaus hat (RpcQos, ServiceMapping, ServiceMatching, WireEncoding, die Bindungsschnittstelle org.omg.dds.rpc.DomainParticipant), prüft der Test nicht.

§7.5.1.2.6 Java: Paarung der Endpunkte nach Aliasen und Zuweisbarkeit

Spec: §7.5.1.2.6, S. 49 — “A client using the base interface can invoke an operation in a service that implements a derived interface as long as the same topic names are used.” Und §7.7.2.5.3 und §7.7.2.5.5: Typ eines Parameters und Rückgabetyp ändern nach den Regeln der Zuweisbarkeit.

Repo: crates/java-omgdds/java/src/main/java/org/zerodds/rtps/TypeConsistency.java, crates/java-omgdds/java/src/main/java/org/zerodds/typelookup/CompleteTypes.java, crates/java-omgdds/java/src/main/java/org/zerodds/rtps/RtpsParticipant.java (typesMatch, askTypeObject, matchAgain), crates/java-omgdds/java/src/main/java/org/zerodds/cdr/TopicTypeSupport.java::matchesByTypeInformation, runtime/java/src/main/java/org/zerodds/ddsrpc/RawTypeSupport.java, runtime/java/src/main/java/org/zerodds/ddsrpc/ZeroDdsParticipant.java::describedReaderQos, crates/lang-rules/src/emit/interface_rust/type_information.rs (minimal, JavaDescription)

Tests: crates/rpc-rust-e2e/tests/java_peer.rs::a_java_client_of_the_base_calls_a_rust_service_of_the_derived_interface, crates/rpc-rust-e2e/tests/java_peer.rs::a_rust_client_of_the_base_calls_a_java_service_of_the_derived_interface, crates/rpc-rust-e2e/tests/java_peer.rs::versions::a_changed_parameter_type_does_not_match_the_java_client, crates/rpc-rust-e2e/tests/java_peer.rs::versions::an_old_java_client_calls_an_old_rust_service, crates/rpc-rust-e2e/tests/java_peer.rs::appended_member::a_member_appended_to_a_mutable_structure_matches_the_java_client, crates/rpc-rust-e2e/tests/java_peer.rs::versions::a_return_type_the_old_one_is_not_assignable_to_does_not_match_the_java_client, crates/java-omgdds/java/src/test/java/org/zerodds/rtps/TypeConsistencyTest.java, crates/lang-rules/tests/enhanced_type_information.rs::every_minimal_identifier_the_information_announces_has_its_object

Status: done — RawTypeSupport.matchesByTypeInformation() lässt die Endpunkte eines beschriebenen Topic-Typs nach XTypes 1.3 §7.6.3.4.2 paaren: gleiche COMPLETE- oder MINIMAL-Kennung, sonst die Zuweisbarkeit des Reader-Typs vom Writer-Typ (§7.2.4.4) auf den COMPLETE-Objekten (TypeConsistency, CompleteTypes, TypeAssignability); ohne TypeInformation auf einer Seite entscheiden die Typnamen. Objekte der Gegenstelle holt RtpsParticipant.askTypeObject mit getTypes (höchstens drei Anfragen je Kennung und Peer; ein Objekt, dessen Serialisierung nicht zu seiner Kennung hasht, wird nicht behalten) und paart nach der Antwort erneut (2d0f809c6e2). Die Java-Beschreibung trägt die MINIMAL-Objekte, die ihre TypeInformation nennt (§7.6.3.3.4, 9b1608508c5); vorher fragte der Rust-Peer danach, bekam keine Antwort und lehnte das Paar nach der Wartezeit der TypeLookup ab. Ein Reader eines beschriebenen Typs kündigt ALLOW_TYPE_COERCION an (d67a980f80b); mit der Vorgabe der PSM (EXACT_TYPE, auf der Leitung DISALLOW_TYPE_COERCION) lehnte der Rust-Dienst den Reply-Reader ab. TypeAssignability nimmt zwei Strukturen ohne Member als zuweisbar (wie crates/types) und trennt int8/uint8 vom octet. Gemessen über RTPS gegen Rust-Peers (Linux-Testhost, java_peer.rs, 8 Tests): Basis gegen abgeleitet in beiden Richtungen, geänderter Parametertyp und auf long long erweiterter Rückgabetyp ohne Match, angehängtes Member mit Match und gelesener Antwort, Kontrolle gleicher Versionen; auf 78f243b596f, vor der Paarung nach Zuweisbarkeit, 5 der 8 rot. Die übrigen Topics der Java-PSM paaren weiter nach dem Typnamen und der TypeConsistencyEnforcement mit PID 0x0072.

§7.11.2 Java: Params und DataWriter-Sichten der PSM

Spec: §7.11.2, S. 67 — “The machine readable files associated with this specification represent the normative language bindings for Java.” In omg-dds-rpc-java.zip tragen die Params DataWriterQos, DataReaderQos, Publisher und Subscriber der DDS-Java-PSM, und Requester.getRequestDataWriter(), getReplyDataReader(), Replier.getRequestDataReader() und getReplyDataWriter() geben DataWriter<TReq> und die verwandten Sichten.

Repo: runtime/java/src/main/java/org/omg/dds/rpc/RequesterParams.java (und ReplierParams, ServiceParams, ClientParams), runtime/java/src/main/java/org/zerodds/ddsrpc/TopicSample.java, RpcTopicTypeSupport.java, PsmEndpoint.java, RpcTopicTypes.java, ZeroDdsParticipant.java, crates/java-omgdds/java/src/main/java/org/zerodds/pub/DataWriterImpl.java::writeSerializedIdentified, crates/java-omgdds/java/src/main/java/org/zerodds/sub/DataReaderImpl.java::takeSerialized, crates/java-omgdds/java/src/main/java/org/zerodds/cdr/TypeSupportResolver.java

Tests: crates/rpc/tests/java/RpcRuntimeRoundtrip.java::psmEntities (läuft in crates/rpc/tests/java_rpc_runtime.rs::the_java_rpc_runtime_and_the_generated_services_run_together), crates/rpc/tests/java/FunctionCallRoundtrip.java::run (läuft in …::the_generated_function_call_client_calls_the_generated_service), crates/rpc-rust-e2e/tests/java_peer.rs (Linux-Testhost, grün)

Status: done — (d6674336a94) Die Params tragen keine Typparameter mehr und haben withDataWriterQos, withDataReaderQos, withPublisher und withSubscriber mit den Gettern; eine DataWriterQos oder DataReaderQos, die sie nennen, ist die QoS der Entität, wie sie steht, und das RpcQos, mit dem die Laufzeit arbeitet, wird daraus abgeleitet; die Entitäten entstehen im genannten Publisher und Subscriber (einer des Teilnehmers, sonst IllegalArgumentException). ServiceParams und ClientParams geben die vier Angaben an ihre Replier und Requester weiter, die Endpunkte der Basis-Interfaces erhalten sie mit sameSettingsAs. Die Entitäten der Bindung über die PSM (ZeroDdsParticipant) sind DataWriter<T> und DataReader<T> der PSM, getypt durch den Topic-Typ, auf einem Topic<T>, wenn die TypeSupport der Params die Klasse ihres Typs nennt (TopicSample.classOf, was jede erzeugte tut): ein über getRequestDataWriter() geschriebener Wert ist das Sample des Topics, wie er steht, Kopf eingeschlossen (TopicSample setzt im Basic Mapping den Kopf aus dem Member header davor und liest ihn dorthin zurück), und die Laufzeit schreibt und liest ihre eigenen Oktette weiter durch dieselben Entitäten (DataWriterImpl.writeSerializedIdentified, DataReaderImpl.takeSerialized mit den beim Empfang behaltenen Oktetten). Die Typregistrierung aus einer Class: TypeSupport.newTypeSupport(<I>_Request.class, …) ergibt über TypeSupportResolver und RpcTopicTypes die Rahmung der Laufzeit statt der reflektiven XCDR2-Codierung. Gemessen (Linux-Testhost): psmEntities erzeugt Requester und Replier über RPCRuntime.getInstance(…), createRequesterParams().withDomainParticipant(…).withPublisher(…).withSubscriber(…).withDataWriterQos(…).withDataReaderQos(…) und createRequester(Class, Class, params); der Request-Writer liegt im Publisher und hat die LIFESPAN der DataWriterQos, der Reply-Reader liegt im Subscriber und hat KEEP_LAST 11 aus der DataReaderQos; die Topics sind durch Calculator_Request und Calculator_Reply getypt; ein Request der Laufzeit und seine Antwort laufen durch die getypten Entitäten; ein über getRequestDataWriter() geschriebener Request erreicht den Replier unter der Identität seines Kopfes; eine über getReplyDataWriter() geschriebene Antwort wird über getReplyDataReader() mit Wert und Kopf gelesen; ein über getRequestDataReader() genommener Request trägt die Identität, die sendRequest zurückgab, und ist danach nicht mehr beim Replier; die aus der Klasse gemachte TypeSupport schreibt dieselben Oktette wie der Requester, und ein Topic daraus trägt einen Request mit Kopf. FunctionCallRoundtrip.java prüft die Class-Formen von ClientEndpoint und ServiceEndpoint für das eigene und das Basis-Interface und die Ablehnung einer fremden Klasse. Ohne getypte Entität geben die vier Operationen null: bei einer Bindung, die nicht die PSM ist (sie lehnt Publisher, Subscriber und PSM-QoS mit RemoteUnsupportedError ab, statt sie zu übergehen), bei einer TypeSupport, die keine Klasse nennt (etwa ein Lambda), und wenn der Teilnehmer das Topic schon unter einem anderen Typ hat. Ein Sample, das der Codec des Topic-Typs nicht lesen kann, hält der getypte Reader ohne Wert (getData() ist null); die Laufzeit sieht seine Oktette und antwortet nach §7.5.2. Weitere Läufe: Maven verify der Java-PSM 925 Tests, 0 Fehler, 3 übersprungen; java_peer.rs 2/2 (Java-Client gegen Rust-Dienst und umgekehrt, mit den getypten Entitäten); lang-rules enhanced_java_calls, java_corpus_compiles, java_psm_mapping, type_pair_java 28 bestanden, 2 ignoriert (die Korpus-Vollläufe, wie vorher).

§7.11.2 Typabbildung nach DDS-Java-PSM

Spec: §7.11.2, S. 67 — “The Java language binding shall use IDL type mapping as per [DDS-Java-PSM].”

Repo: crates/lang-rules/src/adapter/java.rs::java_member_type (Abbildung nach DDS-Java-PSM Clause 9, wählbar mit idlc generate --lang java --java-mapping psm); crates/lang-rules/src/emit/interface_java.rs; Commit 5e078003c162, Interfaces 1214333fd89f

Tests: crates/lang-rules/tests/java_psm_mapping.rs::an_aggregate_is_a_final_class_with_private_state_and_bean_accessors, crates/lang-rules/tests/java_psm_mapping.rs::an_unbounded_sequence_is_a_collection_and_a_bounded_one_an_array, crates/lang-rules/tests/java_psm_mapping.rs::an_interface_is_generated_under_the_psm_mapping, crates/lang-rules/tests/interface_bindings.rs::java_declares_the_same_entities_as_cpp

Status: done — Datentypen und die Typen eines interface (Request, Reply, Parameter, Dienste) lassen sich nach Clause 9 abbilden (Item unten).

§7.11.2 Typabbildung der Interfaces unter DDS-Java-PSM Clause 9

Spec: §7.11.2, S. 67 — wie oben.

Repo: crates/lang-rules/src/emit/interface_java.rs (java_interface_items nimmt --java-mapping psm; die Halter Request, Reply, In, Out, Result behalten öffentliche Felder und nehmen die Typen der Abbildung, der Codec greift über Zugriffsfunktionen auf die Datentypen zu); Commit 1214333fd89f

Tests: crates/lang-rules/tests/java_psm_mapping.rs::an_interface_is_generated_under_the_psm_mapping, crates/lang-rules/tests/java_psm_mapping.rs::an_interface_under_the_psm_mapping_compiles, crates/lang-rules/tests/java_psm_mapping.rs::a_type_pair_under_the_psm_mapping_compiles

Status: done — Basic und Enhanced; die erzeugten Quellen werden mit -Xlint:all -Werror übersetzt. Die Dienste stehen wie die Datentypen in der äußeren Klasse ZdServices (interface_java.rs::OUTER), unter beiden Abbildungen gleich.

§7.11.2 Unterschiede zur C++-Bindung

Spec: §7.11.2, S. 67 — “The following sub clauses describe the entities that are either different or not described in the C++ language bindings.”

Repo: —

Tests: —

Status: n/a (informative) — Einleitung.

§7.11.2.1 Mapping of Exceptions

Spec: §7.11.2.1, S. 67 — Überschrift ohne Text.

Repo: —

Tests: —

Status: n/a (informative) — der Abschnitt hat keinen Inhalt. Die Java-Laufzeit hat fünf Klassen Remote*Error über RuntimeException (runtime/java/src/main/java/org/omg/dds/rpc/).

§7.11.2.2.1 Pakete org.omg.dds und org.omg.dds.rpc

Spec: §7.11.2.2.1, S. 67 — “The org.omg.dds, and org.omg.dds.rpc packages define the interfaces for the request-reply style language binding. Specifically, the language binding includes Requester, Replier, ServiceProxy, RPCEntity, RPCRuntime, SimpleReplierListener, ReplierListener, SimpleRequesterListener, RequesterListener, RequesterParams, ReplierParams, Future, FutureCompletionListener, Sample, and Sample.Iterator.”

Repo: runtime/java/src/main/java/org/omg/dds/rpc/; crates/rpc/src/language_binding.rs (JAVA_PACKAGES, JAVA_REQUEST_REPLY_TYPES); Commit 771f12846807

Tests: crates/rpc/tests/class_summaries_are_declared.rs::the_java_package_declares_every_type_of_the_two_summaries

Status: done — alle 15 Typen sind da; Sample.Iterator ist in Sample.java verschachtelt. Die Form als Interface steht im Item unten.

§7.11.2.2.1 Typen als Interfaces

Spec: §7.11.2.2.1 und §7.11.2.2.3, S. 67 — “define the interfaces”; “RPCRuntime is the only abstract class with placeholder implementation in the Java language binding.”

Repo: runtime/java/src/main/java/org/omg/dds/rpc/ (Requester, Replier, RequesterParams, ReplierParams, Server sind Interfaces; Implementierungen RequesterImpl, ReplierImpl, RequesterParamsImpl, ReplierParamsImpl, ServerImpl; RPCRuntime ist die abstrakte Klasse); Commit 771f12846807

Tests: crates/rpc/tests/java_rpc_runtime.rs::the_java_rpc_runtime_and_the_generated_services_run_together (das Programm übersetzt RequesterImpl implements Requester und die weiteren Implementierungen)

Status: done

§7.11.2.2.2 RPCEntity

Spec: §7.11.2.2.2, S. 67 — “RPCEntity is the base interface extended by all the active entities. It inherits from the DDSObject interface defined in [DDS-Java-PSM] and java.io.Closeable. Its purpose is to provide quick access to the RPCRuntime object.”

Repo: runtime/java/src/main/java/org/omg/dds/rpc/RPCEntity.java; runtime/java/src/main/java/org/omg/dds/rpc/Server.java (extends RPCEntity, Runnable); Commit 8853bea2e973, Zugriff auf die Laufzeit 771f12846807, getRPCRuntime 25d188119b45, Server 17cc6c7ad2a5

Tests: crates/java-omgdds/java/src/test/java/org/omg/dds/rpc/RpcInheritanceTest.java::rpcEntityInheritsDdsObjectAndCloseable, crates/java-omgdds/java/src/test/java/org/omg/dds/rpc/RpcInheritanceTest.java::anEntityAnRpcRuntimeMadeReturnsThatRuntime, crates/rpc/tests/java_rpc_runtime.rs::the_java_entities_are_interfaces_and_the_runtime_makes_services_and_clients (Programm crates/rpc/tests/java/RpcInheritanceTest.java: Server extends RPCEntity)

Status: done — Vererbung, Zugriff auf die Laufzeit und Server als RPCEntity.

§7.11.2.2.3 RPCRuntime: abstrakte Klasse über ServiceEnvironment

Spec: §7.11.2.2.3, S. 67 — “RPCRuntime is the only abstract class with placeholder implementation in the Java language binding. It extends ServiceEnvironment abstract class defined in [DDS-Java-PSM].”

Repo: runtime/java/src/main/java/org/omg/dds/rpc/RPCRuntime.java; Commit 771f12846807

Tests: crates/java-omgdds/java/src/test/java/org/omg/dds/rpc/RpcInheritanceTest.java::aServiceEnvironmentReturnsItself, crates/rpc/tests/java_rpc_runtime.rs::the_java_rpc_runtime_and_the_generated_services_run_together

Status: done

§7.11.2.2.3 RPCRuntime als Singleton und Fabrik aller Entitäten

Spec: §7.11.2.2.3, S. 67 — “Its purpose is to provide access to the RPCRuntime singleton, which serves as a factory for all other entities.”

Repo: runtime/java/src/main/java/org/omg/dds/rpc/RPCRuntime.java (over, createRequester, createReplier, createServer, createRequesterParams, createReplierParams, createServiceParams, createClientParams, createService, createClient, release); Commit 771f12846807, Service und Client 17cc6c7ad2a5

Tests: crates/rpc/tests/java_rpc_runtime.rs::the_java_rpc_runtime_and_the_generated_services_run_together (Programm crates/rpc/tests/java/RpcRuntimeRoundtrip.java: over() liefert die eine Laufzeit eines Participants), crates/rpc/tests/java_rpc_runtime.rs::the_java_entities_are_interfaces_and_the_runtime_makes_services_and_clients (Programm crates/rpc/tests/java/RpcInheritanceTest.java: createService und createClient liefern Entitäten der Laufzeit)

Status: done — over(participant) liefert je Participant dieselbe Instanz; Fabriken für Requester, Replier, Server, Service, Client und die Params.

§7.11.2.2.3 RPCRuntime-Fabrik für Service und Client

Spec: §7.11.2.2.3, S. 67 — wie oben.

Repo: runtime/java/src/main/java/org/omg/dds/rpc/RPCRuntime.java::createService, RPCRuntime.java::createClient (nehmen den Konstruktor der erzeugten <I>ServiceImpl beziehungsweise <I>ClientImpl, auch mit Instanzname); ServiceParams, ClientParams; Commit 17cc6c7ad2a5

Tests: crates/rpc/tests/java_rpc_runtime.rs::the_java_entities_are_interfaces_and_the_runtime_makes_services_and_clients (Programm crates/rpc/tests/java/RpcInheritanceTest.java: service.getEnvironment() == runtime, ein Aufruf des Clients erreicht den Service, Instanzname gebunden, createService ohne Participant wird abgewiesen)

Status: done

§7.11.2.2.4 Future

Spec: §7.11.2.2.4, S. 67 — “The rpc.Future interface extends the java.util.concurrent.Future interface and adds a single operation to specify a FutureCompletionListener.”

Repo: runtime/java/src/main/java/org/omg/dds/rpc/Future.java (setListener); Commit ad892a10764a

Tests: crates/rpc/tests/java_rpc_runtime.rs::the_java_rpc_runtime_and_the_generated_services_run_together

Status: done

§7.11.2.2.5 FutureCompletionListener

Spec: §7.11.2.2.5, S. 68 — “The FutureCompletionListener allows callback notification when the corresponding future becomes ready.”

Repo: runtime/java/src/main/java/org/omg/dds/rpc/FutureCompletionListener.java (onFutureComplete); Commit ad892a10764a

Tests: crates/rpc/tests/java_rpc_runtime.rs::the_java_rpc_runtime_and_the_generated_services_run_together

Status: done

§7.11.2.2.6 Sample

Spec: §7.11.2.2.6, S. 68 — “The rpc.Sample interface extends dds.sub.Sample interface and defines two additional operations to retrieve the SampleIdentity and the related sample identity, if any.”

Repo: runtime/java/src/main/java/org/omg/dds/rpc/Sample.java (identity, relatedIdentity); Commit 771f12846807

Tests: crates/java-omgdds/java/src/test/java/org/omg/dds/rpc/RpcInheritanceTest.java::rpcSampleExtendsThePsmSampleOverTheSameParameter, crates/java-omgdds/java/src/test/java/org/omg/dds/rpc/RpcInheritanceTest.java::anRpcSampleIsAPsmSample

Status: done — zusätzlich deklariert das Interface validData().

§7.11.2.2.7 Sample.Iterator wie in DDS-Java-PSM

Spec: §7.11.2.2.7, S. 68 — “The Sample.Iterator interface is the same as in [DDS-Java-PSM].” DDS-Java-PSM §7.7.2 (S. 16 der PDF dds-java-psm-1.0.pdf): “an iterator that extends java.util.ListIterator”; Seite 17: “the iterator implements the Java.io.Closeable interface”.

Repo: runtime/java/src/main/java/org/omg/dds/rpc/Sample.java (Sample.Iterator extends java.io.Closeable, java.util.ListIterator<Sample<T>>, Sample.iterate; remove, set und add werfen UnsupportedOperationException); Commit 771f12846807, Closeable 17cc6c7ad2a5

Tests: crates/rpc/tests/java_rpc_runtime.rs::the_java_rpc_runtime_and_the_generated_services_run_together (Programm crates/rpc/tests/java/RpcRuntimeRoundtrip.java: instanceof java.util.ListIterator, Rückwärtslauf, remove verweigert), crates/rpc/tests/java_rpc_runtime.rs::the_java_entities_are_interfaces_and_the_runtime_makes_services_and_clients (Programm crates/rpc/tests/java/RpcInheritanceTest.java: Closeable, close() ohne geprüfte Ausnahme, next() nach close(), try-with-resources)

Status: done — ListIterator, lesender Zugriff und java.io.Closeable stimmen.

§7.11.2.2.7 Sample.Iterator: Closeable und returnLoan

Spec: §7.11.2.2.7, S. 68 — wie oben.

Repo: runtime/java/src/main/java/org/omg/dds/rpc/Sample.java::Sample.Iterator (close, returnLoan, isClosed); Commit 17cc6c7ad2a5

Tests: crates/rpc/tests/java_rpc_runtime.rs::the_java_entities_are_interfaces_and_the_runtime_makes_services_and_clients (Programm crates/rpc/tests/java/RpcInheritanceTest.java: Closeable ist Supertyp, close() beendet den Lauf, zweites close() ist erlaubt, das Verlassen von try-with-resources gibt das Loan zurück)

Status: done

§7.11.2.3 Function-call in Java mit den Entitäten von C++

Spec: §7.11.2.3, S. 68 — “Function-Call style language binding in Java shall define the same entities as that of C++.”

Repo: runtime/java/src/main/java/org/omg/dds/rpc/ (Service, ServiceEndpoint, Server, Client, ClientEndpoint, FunctionCallService, FunctionCallClient); crates/lang-rules/src/emit/interface_java.rs (client_interface, service_interface); crates/lang-rules/src/emit/interface_java/calls.rs (client_class, service_class); Commit c512ee365514, Server, ClientEndpoint und Laufzeit 17cc6c7ad2a5

Tests: crates/rpc/src/language_binding.rs::tests::the_java_function_call_types_are_the_cpp_ones, crates/lang-rules/tests/interface_bindings.rs::java_declares_the_same_entities_as_cpp, crates/rpc/tests/java_rpc_runtime.rs::the_generated_function_call_client_calls_the_generated_service, crates/rpc/tests/java_rpc_runtime.rs::the_java_entities_are_interfaces_and_the_runtime_makes_services_and_clients

Status: done — die fünf Entitäten sind deklariert und implementiert; Server bindet einen Service an genau einen Server (IllegalStateException), hat run() und ist ein RPCEntity; ClientEndpoint gibt Request-Writer und Reply-Reader.


Audit-Status

371 done / 0 partial / 0 open / 0 blocked / 44 n/a (informative).

Offene Punkte: keine.


  1. [:alnum:]_ ↩︎