cc_tutorial/tutorials/tutorial23 at master · commschamp/cc_tutorial

Tutorial 23

Reusing definitions from other schemas.

Sometimes a need may arise to reuse some elements (usually fields) of one schema / protocol in the definition of another. It can be useful when common complex encoding rules, like ASN.1 requiring custom code injection need to be reused in multiple independent protocols. Version v5.0 of the CommsDSL Specification allow use of multiple independent schema names when processing multiple schema files and referencing fields of one in another.

Version v5.0 of the commsdsl2comms code generator supports this multi-schema feature, but requires extra command line parameter -s to allow use of multiple schemas names in the definition of the protocol.

This tutorial uses two schema files:

The inter-schema field reference is prefixing the usual field reference with @ + schema name.

<ref field="@t23_ext.ns1.I1" />

The generated code (in include/tutorial23/field/I1.h) defines the field (which inherits the name of the referenced field) as an alias type to the field in the t23_ext namespace:

template <typename TOpt = tutorial23::options::DefaultOptions, typename... TExtraOpts>
using I1 =
    t23_ext::ns1::field::I1<
        TOpt,
        TExtraOpts...
    >;

The definition of the t23_ext::ns1::field::I1 field itself is generated in include/t23_ext/ns1/field folder, i.e. the include folder has two sub-folders for the different namespaces.

The member field of the Msg message definition also references field in the external schema.

<message name="Msg1" id="MsgId.M1" displayName="^Msg1Name">
    <ref field="I1" name="F1" />
    <ref field="@t23_ext.ns1.S1" name="F2" />
</message>

The definition of the Length field in the external t23_ext schema is taken from the previous tutorial22. Instead of referencing it with the <ref> field definition (which is also possible) the schema just copies its definition using reuse property:

<bundle reuse="@t23_ext.ns1.Length" reuseCode="true" />

Please note the usage of the reuseCode property. The reuse one just copies the XML definition of the field without copying any of the custom injected code of the field. Setting reuseCode boolean property ensures that the custom code is also copied. As the result, the Length field definition can be found in the tutorial23 namespace (include/tutorial23/field/Length.h) and cannot be found in t23_ext because it's not really referenced. The Length in the tutorial23 namespace is referenced by the frame:

<frame name="Frame">
    <sync name="Sync">
        <int name="SyncField" type="uint16" defaultValue="0xabdc" />
    </sync>
    <size name="Size" field="Length" />
    <id name="Id" field="MsgId" />
    <payload name="Data" />
</frame>

Also note that the custom injected code of the Length field is located in the folder specifying its original location (dsl_src/include/t23_ext/ns1/field).

Using multiple schemas requires extra attention to specifying protocol options (the classes defined in the include/tutorial23/options folder). The option classes are designed to be folded and outer classes may extend or override options defined by the inner ones. Every schema defines its own independent set of options:

In order to combine them the DefaultOptions of the protocol (tutorial23) schema are expected to wrap and extend the external (t23_ext) one. As the result the ClientSession defines its options in the following way:

using ClientProtocolOptions =
    tutorial23::options::ClientDefaultOptionsT<
        tutorial23::options::DefaultOptionsT<
            t23_ext::options::ClientDefaultOptions
        >
    >;

The ServerSession used even more complex definition:

using ExtProtocolOptions =
    t23_ext::options::DataViewDefaultOptionsT<
        t23_ext::options::ServerDefaultOptions
    >;

using ServerProtocolOptions =
    tutorial23::options::DataViewDefaultOptionsT<
        tutorial23::options::ServerDefaultOptionsT<
            tutorial23::options::DefaultOptionsT<
                ExtProtocolOptions
            >
        >
    >;

Without using options from the t23_ext::options the compilation will fail because t23_ext::ns1::field::S1 field attempts to access the options referencing typename TOpt::t23_ext::ns1::field::S1, which does not exist in the options provided by the tutorial23.

template <typename TOpt = t23_ext::options::DefaultOptions, typename... TExtraOpts>
class S1 : public
    comms::field::String<
        t23_ext::field::FieldBase<>,
        TExtraOpts...,
        typename TOpt::t23_ext::ns1::field::S1,
        comms::option::def::SequenceSerLengthFieldPrefix<typename S1Members<TOpt>::LengthPrefix>
    >

In addition to the complications around the protocol options definitions, which if not done right may result in difficult to understand compilation errors, referencing the fields in another schema may cause problems in different build or packaging systems when multiple independent schemas (protocols) reusing the common one may attempt to generate and overwrite the same common files. To cope with this problem the code generation utilities (commsdsl2comms and others) allow renaming different namespaces to avoid clashing.

However, as was shown in this tutorial the fields which are reuse-ed rather than <ref>-erenced don't generate code in the external namespace. In case the all the schema fields defined this way, the external namespace will be empty and no code for it will be generated. As the result the definition of the protocol options are also getting much simpler.

The bottom line, it is highly recommended to reuse the fields from the external schema rather than <ref>-erence them.

Summary

  • External schema definitions reuse is supported since v5.0 of the CommsDSL and commsdsl code generators.
  • Inter-schema referencing is allowed using @<schema_name>. prefix.
  • When using multiple schemas it is highly recommended to reuse the fields rather than <ref>-erence them.

Read Previous Tutorial <-----------------------> Read Next Tutorial