diff --git a/src/pvxs/data.h b/src/pvxs/data.h index 90b1a41..da4eba9 100644 --- a/src/pvxs/data.h +++ b/src/pvxs/data.h @@ -421,6 +421,17 @@ public: //! Use this definition as a member (eg. sub-structure) in another definition. Member as(const std::string& name) const; + /** Use this definition as a member (eg. sub-structure) in another definition + * with a (limited) type change. + * + * A ``Kind::Compound`` type (eg. ``Struct``) may be changed to another + * Compound type (eg. ``StructA``). However. changes between Compound + * and non-Compound are not allowed. + * + * @since UNRELEASED + */ + Member as(TypeCode code, const std::string& name) const; + private: std::shared_ptr _append_start(); static diff --git a/src/type.cpp b/src/type.cpp index 46d2282..783228f 100644 --- a/src/type.cpp +++ b/src/type.cpp @@ -336,6 +336,17 @@ Member TypeDef::as(const std::string& name) const return ret; } +Member TypeDef::as(TypeCode code, const std::string& name) const +{ + Member ret(as(name)); + + if((code.kind()==Kind::Compound) ^ (ret.code.kind()==Kind::Compound)) + throw std::logic_error("as() may change between Compound and non-Compound"); + + ret.code = code; + return ret; +} + std::shared_ptr TypeDef::_append_start() { if(!top || (top->code.scalarOf()!=TypeCode::Struct && top->code.scalarOf()!=TypeCode::Union)) diff --git a/test/testtype.cpp b/test/testtype.cpp index 5a90891..77491b7 100644 --- a/test/testtype.cpp +++ b/test/testtype.cpp @@ -385,9 +385,10 @@ void testTypeDefAppend() { testDiag("%s()", __func__); - auto base = TypeDef(TypeCode::Struct, "epics:nt/NTDummy:0.0", { - members::UInt32("A"), - }).create(); + TypeDef start(TypeCode::Struct, "epics:nt/NTDummy:0.0", { + members::UInt32("A"), + }); + auto base = start.create(); auto sub = TypeDef(base); sub += { @@ -396,13 +397,47 @@ void testTypeDefAppend() auto amend = sub.create(); + start += { + members::UInt32("C"), + }; + auto extend = start.create(); + testEq(base.id(), "epics:nt/NTDummy:0.0"); testEq(base["A"].type(), TypeCode::UInt32); testEq(base["B"].type(), TypeCode::Null); + testEq(base["C"].type(), TypeCode::Null); testEq(amend.id(), "epics:nt/NTDummy:0.0"); testEq(amend["A"].type(), TypeCode::UInt32); testEq(amend["B"].type(), TypeCode::UInt32); + testEq(amend["C"].type(), TypeCode::Null); + + testEq(extend.id(), "epics:nt/NTDummy:0.0"); + testEq(extend["A"].type(), TypeCode::UInt32); + testEq(extend["B"].type(), TypeCode::Null); + testEq(extend["C"].type(), TypeCode::UInt32); +} + +void testTypeDefAppendIncremental() +{ + testDiag("%s()", __func__); + + TypeDef part(TypeCode::Struct, { + members::UInt32("x"), + }); + + TypeDef whole(TypeCode::Struct, { + members::UInt32("a"), + part.as(TypeCode::StructA, "b"), + }); + + testStrEq(std::string(SB()<