From a35230a4a68284a7d76d4f4e201f3d57cd578613 Mon Sep 17 00:00:00 2001 From: Alex Robenko Date: Wed, 11 Dec 2024 09:28:25 +1000 Subject: [PATCH] Supporting "reuse" and "reuseCode" properties for -s. --- lib/src/parse/FieldImpl.cpp | 1 + lib/src/parse/MessageImpl.cpp | 59 ++++++++++++++++++++++++++ lib/src/parse/MessageImpl.h | 73 ++++++++++++++++++++++++++++++++- lib/src/parse/ProtocolImpl.cpp | 5 +++ lib/src/parse/ProtocolImpl.h | 1 + lib/test/message/Schema32.xml | 43 +++++++++++++++++++ lib/test/message/messageTest.th | 35 ++++++++++++++++ 7 files changed, 216 insertions(+), 1 deletion(-) create mode 100644 lib/test/message/Schema32.xml diff --git a/lib/src/parse/FieldImpl.cpp b/lib/src/parse/FieldImpl.cpp index b3c11f3f..0425eb73 100644 --- a/lib/src/parse/FieldImpl.cpp +++ b/lib/src/parse/FieldImpl.cpp @@ -1076,6 +1076,7 @@ bool FieldImpl::checkReuse() return false; } + m_state.m_copyCodeFrom.clear(); auto codeIter = m_props.find(codeProp); if (codeIter == m_props.end()) { break; diff --git a/lib/src/parse/MessageImpl.cpp b/lib/src/parse/MessageImpl.cpp index caa40558..e0a1afc4 100644 --- a/lib/src/parse/MessageImpl.cpp +++ b/lib/src/parse/MessageImpl.cpp @@ -96,6 +96,7 @@ bool MessageImpl::parse() } return + checkReuse() && updateName() && updateDisplayName() && updateDescription() && @@ -361,6 +362,8 @@ const XmlWrap::NamesList& MessageImpl::commonProps() common::constructAsReadCondStr(), common::constructAsValidCondStr(), common::failOnInvalidStr(), + common::reuseStr(), + common::reuseCodeStr(), }; return CommonNames; @@ -401,6 +404,62 @@ XmlWrap::NamesList MessageImpl::allNames() return names; } +bool MessageImpl::checkReuse() +{ + auto& propStr = common::reuseStr(); + if (!validateSinglePropInstance(propStr)) { + return false; + } + + auto iter = m_props.find(propStr); + if (iter == m_props.end()) { + return true; + } + + if (!m_protocol.isMessageReuseSupported()) { + logWarning() << XmlWrap::logPrefix(getNode()) << + "Property \"" << propStr << "\" is not supported for DSL version " << m_protocol.currSchema().dslVersion() << ", ignoring..."; + return true; + } + + auto& valueStr = iter->second; + auto* msg = m_protocol.findMessage(valueStr); + if (msg == nullptr) { + logError() << XmlWrap::logPrefix(getNode()) << + "The message \"" << valueStr << "\" hasn't been recorded yet."; + return false; + } + + assert(msg != this); + Base::reuseState(*msg); + m_state = msg->m_state; + + do { + auto& codeProp = common::reuseCodeStr(); + if (!validateSinglePropInstance(codeProp, false)) { + return false; + } + + m_state.m_copyCodeFrom.clear(); + auto codeIter = m_props.find(codeProp); + if (codeIter == m_props.end()) { + break; + } + + bool copyCode = false; + if (!validateAndUpdateBoolPropValue(codeProp, copyCode)) { + return false; + } + + if (!copyCode) { + break; + } + + m_state.m_copyCodeFrom = valueStr; + } while (false); + return true; +} + bool MessageImpl::updateName() { bool mustHave = m_state.m_name.empty(); diff --git a/lib/src/parse/MessageImpl.h b/lib/src/parse/MessageImpl.h index a32dae3d..8fe9db36 100644 --- a/lib/src/parse/MessageImpl.h +++ b/lib/src/parse/MessageImpl.h @@ -15,10 +15,12 @@ #pragma once +#include #include #include #include -#include +#include +#include #include "commsdsl/parse/Message.h" @@ -197,6 +199,74 @@ class MessageImpl final : public Object OptCondImplPtr m_validCond; bool m_customizable = false; bool m_failOnInvalid = false; + + ReusableState() = default; + ReusableState(ReusableState&&) = default; + + auto basicForwardAsTuple() + { + return + std::forward_as_tuple( + m_name, + m_displayName, + m_description, + m_id = 0, + m_order, + m_validateMinLength, + // m_fields, + // m_aliases, + m_platforms, + m_sender, + m_readOverride, + m_writeOverride, + m_refreshOverride, + m_lengthOverride, + m_validOverride, + m_nameOverride, + m_copyCodeFrom, + // m_construct, + // m_readCond, + // m_validCond, + m_customizable, + m_failOnInvalid + ); + } + + auto basicForwardAsTuple() const + { + return const_cast(this)->basicForwardAsTuple(); + } + + ReusableState& operator=(const ReusableState& other) + { + basicForwardAsTuple() = other.basicForwardAsTuple(); + + m_fields.clear(); + m_fields.reserve(other.m_fields.size()); + for (auto& f : other.m_fields) { + m_fields.push_back(f->clone()); + } + + m_aliases.clear(); + m_aliases.reserve(other.m_aliases.size()); + for (auto& a : other.m_aliases) { + m_aliases.push_back(a->clone()); + } + + if (other.m_construct) { + m_construct = other.m_construct->clone(); + } + + if (other.m_readCond) { + m_readCond = other.m_readCond->clone(); + } + + if (other.m_validCond) { + m_validCond = other.m_validCond->clone(); + } + + return *this; + } }; LogWrapper logError() const; @@ -214,6 +284,7 @@ class MessageImpl final : public Object bool validateAndUpdateOverrideTypePropValue(const std::string& propName, OverrideType& value); bool validateAndUpdateBoolPropValue(const std::string& propName, bool& value, bool mustHave = false); void reportUnexpectedPropertyValue(const std::string& propName, const std::string& propValue); + bool checkReuse(); bool updateName(); bool updateDescription(); bool updateDisplayName(); diff --git a/lib/src/parse/ProtocolImpl.cpp b/lib/src/parse/ProtocolImpl.cpp index 6ed8fb36..0db019c0 100644 --- a/lib/src/parse/ProtocolImpl.cpp +++ b/lib/src/parse/ProtocolImpl.cpp @@ -416,6 +416,11 @@ bool ProtocolImpl::isValidateMinLengthForFieldsSupported() const return isFeatureSupported(7U); } +bool ProtocolImpl::isMessageReuseSupported() const +{ + return isFeatureSupported(7U); +} + void ProtocolImpl::cbXmlErrorFunc(void* userData, const xmlError* err) { reinterpret_cast(userData)->handleXmlError(err); diff --git a/lib/src/parse/ProtocolImpl.h b/lib/src/parse/ProtocolImpl.h index 1cf60e03..21626f1a 100644 --- a/lib/src/parse/ProtocolImpl.h +++ b/lib/src/parse/ProtocolImpl.h @@ -121,6 +121,7 @@ class ProtocolImpl bool isExistsCheckInConditionalsSupported() const; bool isValidValueInStringAndDataSupported() const; bool isValidateMinLengthForFieldsSupported() const; + bool isMessageReuseSupported() const; void setMultipleSchemasEnabled(bool value) { diff --git a/lib/test/message/Schema32.xml b/lib/test/message/Schema32.xml new file mode 100644 index 00000000..765c4da8 --- /dev/null +++ b/lib/test/message/Schema32.xml @@ -0,0 +1,43 @@ + + + + Testing + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/test/message/messageTest.th b/lib/test/message/messageTest.th index 505c4ed7..d46d613d 100644 --- a/lib/test/message/messageTest.th +++ b/lib/test/message/messageTest.th @@ -38,6 +38,7 @@ public: void test29(); void test30(); void test31(); + void test32(); }; void MessageTestSuite::setUp() @@ -666,4 +667,38 @@ void MessageTestSuite::test31() TS_ASSERT(msg1.isFailOnInvalid()); auto msg1ValidCond = msg1.validCond(); TS_ASSERT_EQUALS(msg1ValidCond.kind(), commsdsl::parse::OptCond::Kind::List); +} + +void MessageTestSuite::test32() +{ + auto protocol = prepareProtocol(SCHEMAS_DIR "/Schema32.xml"); + TS_ASSERT(protocol); + + auto namespaces = protocol->lastParsedSchema().namespaces(); + TS_ASSERT_EQUALS(namespaces.size(), 1U); + + auto& ns = namespaces.front(); + TS_ASSERT(ns.name().empty()); + + auto messages = ns.messages(); + { + TS_ASSERT_LESS_THAN_EQUALS(1U, messages.size()); + + auto& msg1 = messages[0]; + TS_ASSERT(msg1.isFailOnInvalid()); + TS_ASSERT_EQUALS(msg1.fields().size(), 2U); + auto msg1ValidCond = msg1.validCond(); + TS_ASSERT_EQUALS(msg1ValidCond.kind(), commsdsl::parse::OptCond::Kind::List); + } + + { + TS_ASSERT_LESS_THAN_EQUALS(2U, messages.size()); + + auto& msg2 = messages[1]; + TS_ASSERT(msg2.isFailOnInvalid()); + TS_ASSERT_EQUALS(msg2.fields().size(), 3U); + TS_ASSERT_EQUALS(msg2.copyCodeFrom(), "Msg1"); + auto msg1ValidCond = msg2.validCond(); + TS_ASSERT_EQUALS(msg1ValidCond.kind(), commsdsl::parse::OptCond::Kind::List); + } } \ No newline at end of file