From 5f781ac91ef0ab8f6b053ea5abfaf183a9724b98 Mon Sep 17 00:00:00 2001 From: soldier-sky Date: Wed, 18 Mar 2026 22:25:06 +0530 Subject: [PATCH 1/2] mw/com/impl: Add SetHandler support for SkeletonField Implement RegisterSetHandler() method to allow users to register callbacks for handling remote Set requests on skeleton fields. Issue: SWP-249527 --- score/mw/com/impl/BUILD | 3 + score/mw/com/impl/skeleton_event.h | 16 +- score/mw/com/impl/skeleton_field.h | 232 +++++++++++++++++++----- score/mw/com/impl/skeleton_field_base.h | 12 ++ score/mw/com/impl/traits.h | 15 +- 5 files changed, 219 insertions(+), 59 deletions(-) diff --git a/score/mw/com/impl/BUILD b/score/mw/com/impl/BUILD index 1f78b91aa..fdf1ff4f2 100644 --- a/score/mw/com/impl/BUILD +++ b/score/mw/com/impl/BUILD @@ -147,9 +147,11 @@ cc_library( deps = [ ":skeleton_event", ":skeleton_field_base", + "//score/mw/com/impl/methods:skeleton_method", "//score/mw/com/impl/mocking:i_skeleton_field", "//score/mw/com/impl/plumbing:field", "//score/mw/com/impl/plumbing:sample_allocatee_ptr", + "//score/mw/com/impl/methods:method_signature_element_ptr", "@score_baselibs//score/language/futurecpp", "@score_baselibs//score/result", "@score_logging//score/mw/log", @@ -246,6 +248,7 @@ cc_library( deps = [ ":error", ":skeleton_event_base", + "//score/mw/com/impl/methods:skeleton_method_base", "@score_baselibs//score/language/futurecpp", "@score_baselibs//score/result", "@score_logging//score/mw/log", diff --git a/score/mw/com/impl/skeleton_event.h b/score/mw/com/impl/skeleton_event.h index 2face4332..f5f768e1c 100644 --- a/score/mw/com/impl/skeleton_event.h +++ b/score/mw/com/impl/skeleton_event.h @@ -36,7 +36,9 @@ namespace score::mw::com::impl // False Positive: this is a normal forward declaration. // coverity[autosar_cpp14_m3_2_3_violation] -template +template class SkeletonField; template @@ -51,7 +53,8 @@ class SkeletonEvent : public SkeletonEventBase // SkeletonField uses composition pattern to reuse code from SkeletonEvent. These two classes also have shared // private APIs which necessitates the use of the friend keyword. // coverity[autosar_cpp14_a11_3_1_violation] - friend class SkeletonField; + template + friend class SkeletonField; // Empty struct that is used to make the second constructor only accessible to SkeletonEvent and SkeletonField (as // the latter is a friend). @@ -234,7 +237,7 @@ ResultBlank SkeletonEvent::Send(const EventType& sample_value) n if (!send_result.has_value()) { score::mw::log::LogError("lola") << "SkeletonEvent::Send with copy failed: " << send_result.error().Message() - << ": " << send_result.error().UserMessage(); + << ": " << send_result.error().UserMessage(); return MakeUnexpected(ComErrc::kBindingFailure); } return send_result; @@ -262,7 +265,7 @@ ResultBlank SkeletonEvent::Send(SampleAllocateePtr sa if (!send_result.has_value()) { score::mw::log::LogError("lola") << "SkeletonEvent::Send zero copy failed: " << send_result.error().Message() - << ": " << send_result.error().UserMessage(); + << ": " << send_result.error().UserMessage(); return MakeUnexpected(ComErrc::kBindingFailure); } return send_result; @@ -287,7 +290,7 @@ Result> SkeletonEvent::Alloca if (!allocate_result.has_value()) { score::mw::log::LogError("lola") << "SkeletonEvent::Allocate failed: " << allocate_result.error().Message() - << ": " << allocate_result.error().UserMessage(); + << ": " << allocate_result.error().UserMessage(); return MakeUnexpected(ComErrc::kBindingFailure); } return allocate_result; @@ -297,8 +300,7 @@ template auto SkeletonEvent::GetTypedEventBinding() const noexcept -> SkeletonEventBinding* { auto* const typed_binding = dynamic_cast*>(binding_.get()); - SCORE_LANGUAGE_FUTURECPP_ASSERT_PRD_MESSAGE(typed_binding != nullptr, - "Downcast to SkeletonEventBinding failed!"); + SCORE_LANGUAGE_FUTURECPP_ASSERT_PRD_MESSAGE(typed_binding != nullptr, "Downcast to SkeletonEventBinding failed!"); return typed_binding; } diff --git a/score/mw/com/impl/skeleton_field.h b/score/mw/com/impl/skeleton_field.h index b364d93f2..7be228b0b 100644 --- a/score/mw/com/impl/skeleton_field.h +++ b/score/mw/com/impl/skeleton_field.h @@ -17,6 +17,7 @@ #include "score/mw/com/impl/plumbing/skeleton_field_binding_factory.h" #include "score/mw/com/impl/skeleton_event.h" #include "score/mw/com/impl/skeleton_field_base.h" +#include "score/mw/com/impl/methods/skeleton_method.h" #include "score/mw/com/impl/mocking/i_skeleton_field.h" @@ -27,18 +28,50 @@ #include #include +#include #include namespace score::mw::com::impl { -template +namespace detail +{ +/// Tag types for constructor overload disambiguation based on EnableSet template parameter. +struct EnableSetOnlyTag +{ +}; +struct EnableNeitherTag +{ +}; +} // namespace detail + +template class SkeletonField : public SkeletonFieldBase { public: using FieldType = SampleDataType; + using SetHandlerType = score::cpp::callback; - SkeletonField(SkeletonBase& parent, const std::string_view field_name); + /// \brief Constructs a SkeletonField with setter enabled. Normal ctor used in production code. + /// + /// \param parent Skeleton that contains this field. + /// \param field_name Field name of the field. + /// \param detail::EnableSetOnlyTag This parameter is only used for constructor overload disambiguation and + /// has no semantic meaning. The tag disambiguates the setter-enabled ctor from the no-setter ctor, as + /// otherwise both would have the same signature. + template > + SkeletonField(SkeletonBase& parent, const std::string_view field_name, detail::EnableSetOnlyTag = {}); + + /// \brief Constructs a SkeletonField with no setter. Normal ctor used in production code. + /// + /// \param parent Skeleton that contains this field. + /// \param field_name Field name of the field. + /// \param detail::EnableNeitherTag This parameter is only used for constructor overload disambiguation and + /// has no semantic meaning. + template > + SkeletonField(SkeletonBase& parent, const std::string_view field_name, detail::EnableNeitherTag = {}); /// Constructor that allows to set the binding directly. /// @@ -92,6 +125,29 @@ class SkeletonField : public SkeletonFieldBase skeleton_field_mock_ = &skeleton_field_mock; } + // SFINAE-gated: only exists when EnableSet == true + template ::type = 0> + ResultBlank RegisterSetHandler(SetHandlerType handler) { + auto wrapped_callback = [this, user_callback = std::move(handler)] + (FieldType new_value) -> Result { + // Allow user to validate/modify the value in-place + user_callback(new_value); + + // Store the (possibly modified) value as the latest field value + auto update_result = this->Update(new_value); + if (!update_result.has_value()) { + return MakeUnexpected(update_result.error()); + } + + // Return the accepted value to the proxy + return new_value; + }; + + is_set_handler_registered_ = true; + return set_method_.get()->RegisterHandler(std::move(wrapped_callback)); + } + private: bool IsInitialValueSaved() const noexcept override { @@ -107,40 +163,130 @@ class SkeletonField : public SkeletonFieldBase std::unique_ptr initial_field_value_; ISkeletonField* skeleton_field_mock_; + + // Zero-cost conditional storage: unique_ptr when EnableSet=true, zero-size tag when false. + using SetMethodType = std::conditional_t(FieldType)>>, + detail::EnableSetOnlyTag>; + SetMethodType set_method_; + + // Tracks whether RegisterSetHandler() has been called. Zero-cost when EnableSet=false. + using IsSetHandlerRegisteredType = std::conditional_t; + IsSetHandlerRegisteredType is_set_handler_registered_{}; + + // EnableSet=true: checks the flag; EnableSet=false: no setter, no handler required. + bool IsSetHandlerRegistered() const noexcept override + { + if constexpr (EnableSet) + { + return is_set_handler_registered_; + } + return true; + } + + /// \brief Private delegating constructor used by the setter-enabled public ctor. + /// Receives already-constructed objects so that we can pass the event pointer to SkeletonFieldBase before + /// storing it here, mirroring the ProxyField pattern. + template > + SkeletonField(SkeletonBase& parent, + std::unique_ptr> skeleton_event_dispatch, + std::unique_ptr(FieldType)>> set_method, + const std::string_view field_name); + + /// \brief Private delegating constructor used by the no-setter public ctor. + template > + SkeletonField(SkeletonBase& parent, + std::unique_ptr> skeleton_event_dispatch, + const std::string_view field_name); }; -template -SkeletonField::SkeletonField(SkeletonBase& parent, const std::string_view field_name) - : SkeletonFieldBase{parent, +/// \brief Public ctor — EnableSet=true: delegates to the private ctor that also creates the set method. +template +template +SkeletonField::SkeletonField(SkeletonBase& parent, + const std::string_view field_name, + detail::EnableSetOnlyTag) + : SkeletonField{parent, + std::make_unique>( + parent, + field_name, + SkeletonFieldBindingFactory::CreateEventBinding( + SkeletonBaseView{parent}.GetAssociatedInstanceIdentifier(), + parent, + field_name), + typename SkeletonEvent::FieldOnlyConstructorEnabler{}), + std::make_unique(FieldType)>>( + parent, std::string(field_name) + "_Set"), + field_name} +{ +} + +/// \brief Public ctor — EnableSet=false: delegates to the private ctor with no set method. +template +template +SkeletonField::SkeletonField(SkeletonBase& parent, + const std::string_view field_name, + detail::EnableNeitherTag) + : SkeletonField{parent, + std::make_unique>( + parent, field_name, - std::make_unique>( + SkeletonFieldBindingFactory::CreateEventBinding( + SkeletonBaseView{parent}.GetAssociatedInstanceIdentifier(), parent, - field_name, - SkeletonFieldBindingFactory::CreateEventBinding( - SkeletonBaseView{parent}.GetAssociatedInstanceIdentifier(), - parent, - field_name), - typename SkeletonEvent::FieldOnlyConstructorEnabler{})}, + field_name), + typename SkeletonEvent::FieldOnlyConstructorEnabler{}), + field_name} +{ +} + +/// \brief Testing ctor: binding is provided directly (used with mock bindings in tests). +template +SkeletonField::SkeletonField(SkeletonBase& skeleton_base, + const std::string_view field_name, + std::unique_ptr> binding) + : SkeletonField{skeleton_base, + std::make_unique>(skeleton_base, field_name, std::move(binding)), + field_name} +{ +} + +/// \brief Private delegating ctor — setter enabled. Receives fully-constructed objects. +/// By constructing set_method_ here and passing the event pointer to SkeletonFieldBase first, +/// we guarantee the base class pointer is stable before we store set_method_. +template +template +SkeletonField::SkeletonField( + SkeletonBase& parent, + std::unique_ptr> skeleton_event_dispatch, + std::unique_ptr(FieldType)>> set_method, + const std::string_view field_name) + : SkeletonFieldBase{parent, field_name, std::move(skeleton_event_dispatch)}, initial_field_value_{nullptr}, - skeleton_field_mock_{nullptr} + skeleton_field_mock_{nullptr}, + set_method_{std::move(set_method)} { SkeletonBaseView skeleton_base_view{parent}; skeleton_base_view.RegisterField(field_name, *this); } -template -SkeletonField::SkeletonField(SkeletonBase& skeleton_base, - const std::string_view field_name, - std::unique_ptr> binding) - : SkeletonFieldBase{skeleton_base, - field_name, - std::make_unique>(skeleton_base, field_name, std::move(binding))}, +/// \brief Private delegating ctor — no setter. Receives the already-constructed event. +template +template +SkeletonField::SkeletonField( + SkeletonBase& parent, + std::unique_ptr> skeleton_event_dispatch, + const std::string_view field_name) + : SkeletonFieldBase{parent, field_name, std::move(skeleton_event_dispatch)}, + initial_field_value_{nullptr}, skeleton_field_mock_{nullptr} { + SkeletonBaseView skeleton_base_view{parent}; + skeleton_base_view.RegisterField(field_name, *this); } -template -SkeletonField::SkeletonField(SkeletonField&& other) noexcept +template +SkeletonField::SkeletonField(SkeletonField&& other) noexcept : SkeletonFieldBase(static_cast(other)), // known llvm bug (https://github.com/llvm/llvm-project/issues/63202) // This usage is safe because the previous line only moves the base class portion via static_cast. @@ -148,15 +294,16 @@ SkeletonField::SkeletonField(SkeletonField&& other) noexcept // so it's still valid to access it here for moving into our own member. // coverity[autosar_cpp14_a12_8_3_violation] This is a false-positive. initial_field_value_{std::move(other.initial_field_value_)}, - skeleton_field_mock_{other.skeleton_field_mock_} + skeleton_field_mock_{other.skeleton_field_mock_}, + set_method_{std::move(other.set_method_)} { // Since the address of this event has changed, we need update the address stored in the parent skeleton. SkeletonBaseView skeleton_base_view{skeleton_base_.get()}; skeleton_base_view.UpdateField(field_name_, *this); } -template -auto SkeletonField::operator=(SkeletonField&& other) & noexcept -> SkeletonField& +template +auto SkeletonField::operator=(SkeletonField&& other) & noexcept -> SkeletonField& { if (this != &other) { @@ -164,6 +311,7 @@ auto SkeletonField::operator=(SkeletonField&& other) & noexcept initial_field_value_ = std::move(other.initial_field_value_); skeleton_field_mock_ = std::move(other.skeleton_field_mock_); + set_method_ = std::move(other.set_method_); // Since the address of this event has changed, we need update the address stored in the parent skeleton. SkeletonBaseView skeleton_base_view{skeleton_base_.get()}; @@ -179,8 +327,8 @@ auto SkeletonField::operator=(SkeletonField&& other) & noexcept /// field cannot be set until the Skeleton has been set up via Skeleton::OfferService(). Therefore, we create a /// callback that will update the field value with sample_value which will be called in the first call to /// SkeletonFieldBase::PrepareOffer(). -template -ResultBlank SkeletonField::Update(const FieldType& sample_value) noexcept +template +ResultBlank SkeletonField::Update(const FieldType& sample_value) noexcept { if (skeleton_field_mock_ != nullptr) { @@ -197,8 +345,8 @@ ResultBlank SkeletonField::Update(const FieldType& sample_value) /// \brief FieldType is previously allocated by middleware and provided by the user to indicate that he is finished /// filling the provided pointer with live data. Dispatches to SkeletonEvent::Send() -template -ResultBlank SkeletonField::Update(SampleAllocateePtr sample) noexcept +template +ResultBlank SkeletonField::Update(SampleAllocateePtr sample) noexcept { if (skeleton_field_mock_ != nullptr) { @@ -213,8 +361,8 @@ ResultBlank SkeletonField::Update(SampleAllocateePtr /// /// This function cannot be currently called to set the initial value of a field as the shared memory must be first /// set up in the Skeleton::PrepareOffer() before the user can obtain / use a SampleAllocateePtr. -template -Result> SkeletonField::Allocate() noexcept +template +Result> SkeletonField::Allocate() noexcept { if (skeleton_field_mock_ != nullptr) { @@ -224,24 +372,22 @@ Result> SkeletonField::Alloca // This check can be removed when Ticket-104261 is implemented if (!was_prepare_offer_called_) { - score::mw::log::LogWarn("lola") - << "Lola currently doesn't support zero-copy Allocate() before OfferService() is " - "called as the shared memory is not setup until OfferService() is called."; + score::mw::log::LogWarn("lola") << "Lola currently doesn't support zero-copy Allocate() before OfferService() is " + "called as the shared memory is not setup until OfferService() is called."; return MakeUnexpected(ComErrc::kBindingFailure); } return GetTypedEvent()->Allocate(); } -template +template // Suppress "AUTOSAR C++14 A0-1-3" rule finding. This rule states: "Every function defined in an anonymous // namespace, or static function with internal linkage, or private member function shall be used.". // False-positive, method is used in the base class in PrepareOffer(). // coverity[autosar_cpp14_a0_1_3_violation : FALSE] -ResultBlank SkeletonField::DoDeferredUpdate() noexcept +ResultBlank SkeletonField::DoDeferredUpdate() noexcept { - SCORE_LANGUAGE_FUTURECPP_ASSERT_MESSAGE( - initial_field_value_ != nullptr, - "Initial field value containing a value is a precondition for DoDeferredUpdate."); + SCORE_LANGUAGE_FUTURECPP_ASSERT_MESSAGE(initial_field_value_ != nullptr, + "Initial field value containing a value is a precondition for DoDeferredUpdate."); const auto update_result = UpdateImpl(*initial_field_value_); if (!update_result.has_value()) { @@ -253,14 +399,14 @@ ResultBlank SkeletonField::DoDeferredUpdate() noexcept return ResultBlank{}; } -template -ResultBlank SkeletonField::UpdateImpl(const FieldType& sample_value) noexcept +template +ResultBlank SkeletonField::UpdateImpl(const FieldType& sample_value) noexcept { return GetTypedEvent()->Send(sample_value); } -template -auto SkeletonField::GetTypedEvent() const noexcept -> SkeletonEvent* +template +auto SkeletonField::GetTypedEvent() const noexcept -> SkeletonEvent* { auto* const typed_event = dynamic_cast*>(skeleton_event_dispatch_.get()); SCORE_LANGUAGE_FUTURECPP_ASSERT_PRD_MESSAGE(typed_event != nullptr, "Downcast to SkeletonEvent failed!"); diff --git a/score/mw/com/impl/skeleton_field_base.h b/score/mw/com/impl/skeleton_field_base.h index b38974f13..e1762cf8b 100644 --- a/score/mw/com/impl/skeleton_field_base.h +++ b/score/mw/com/impl/skeleton_field_base.h @@ -15,6 +15,7 @@ #include "score/mw/com/impl/com_error.h" #include "score/mw/com/impl/skeleton_event_base.h" +#include "score/mw/com/impl/methods/skeleton_method_base.h" #include "score/mw/log/logging.h" #include "score/result/result.h" @@ -61,6 +62,14 @@ class SkeletonFieldBase // after calling PrepareOffer() on the binding if (!was_prepare_offer_called_) { + // If the field is configured with a setter, the application must register + // a set handler before calling OfferService(), otherwise Offer() shall fail. + if (!IsSetHandlerRegistered()) + { + score::mw::log::LogWarn("lola") << "Set handler must be registered before offering field: "<< field_name_; + return MakeUnexpected(ComErrc::kSetHandlerNotSet); + } + if (!IsInitialValueSaved()) { score::mw::log::LogWarn("lola") << "Initial value must be set before offering field: " << field_name_; @@ -121,6 +130,9 @@ class SkeletonFieldBase /// \brief Returns whether the initial value has been saved by the user to be used by DoDeferredUpdate virtual bool IsInitialValueSaved() const noexcept = 0; + /// \brief Returns whether a set handler has been registered. + virtual bool IsSetHandlerRegistered() const noexcept = 0; + /// \brief Sets the initial value of the field. /// /// The existence of the value is a precondition of this function, so IsInitialValueSaved() should be checked before diff --git a/score/mw/com/impl/traits.h b/score/mw/com/impl/traits.h index 5f2ce1b94..29a5a708e 100644 --- a/score/mw/com/impl/traits.h +++ b/score/mw/com/impl/traits.h @@ -150,8 +150,8 @@ class SkeletonTrait template using Event = SkeletonEvent; - template - using Field = SkeletonField; + template + using Field = SkeletonField; template using Method = SkeletonMethod; @@ -215,9 +215,8 @@ class SkeletonWrapperClass : public Interface SkeletonWrapperClass skeleton_wrapper(instance_identifier, std::move(skeleton_binding)); if (!skeleton_wrapper.AreBindingsValid()) { - ::score::mw::log::LogError("lola") - << "Could not create SkeletonWrapperClass as Skeleton binding or service " - "element bindings could not be created."; + ::score::mw::log::LogError("lola") << "Could not create SkeletonWrapperClass as Skeleton binding or service " + "element bindings could not be created."; return MakeUnexpected(ComErrc::kBindingFailure); } @@ -268,10 +267,8 @@ class SkeletonWrapperClass : public Interface std::unordered_map>> instance_identifier_creation_results) { - score::cpp::ignore = - instance_specifier_creation_results_.emplace(std::move(instance_specifier_creation_results)); - score::cpp::ignore = - instance_identifier_creation_results_.emplace(std::move(instance_identifier_creation_results)); + score::cpp::ignore = instance_specifier_creation_results_.emplace(std::move(instance_specifier_creation_results)); + score::cpp::ignore = instance_identifier_creation_results_.emplace(std::move(instance_identifier_creation_results)); } static void ClearCreationResults() From ff9ef7dc63d2adb0eb7b054370ae99e01a7c257d Mon Sep 17 00:00:00 2001 From: soldier-sky Date: Fri, 20 Mar 2026 13:31:47 +0530 Subject: [PATCH 2/2] mw/com/impl: Fix failing tests of Skeleton Field Fix testcases failing due to missing implementation of pure virtual IsSetHandlerRegistered Issue: SWP-249527 --- score/mw/com/impl/BUILD | 2 +- score/mw/com/impl/skeleton_base_test.cpp | 5 ++ score/mw/com/impl/skeleton_event.h | 13 ++- score/mw/com/impl/skeleton_field.h | 87 ++++++++++--------- score/mw/com/impl/skeleton_field_base.h | 5 +- .../mw/com/impl/skeleton_field_base_test.cpp | 10 +++ .../impl/tracing/skeleton_tracing_test.cpp | 5 ++ score/mw/com/impl/traits.h | 11 ++- 8 files changed, 82 insertions(+), 56 deletions(-) diff --git a/score/mw/com/impl/BUILD b/score/mw/com/impl/BUILD index fdf1ff4f2..7bac46d8b 100644 --- a/score/mw/com/impl/BUILD +++ b/score/mw/com/impl/BUILD @@ -147,11 +147,11 @@ cc_library( deps = [ ":skeleton_event", ":skeleton_field_base", + "//score/mw/com/impl/methods:method_signature_element_ptr", "//score/mw/com/impl/methods:skeleton_method", "//score/mw/com/impl/mocking:i_skeleton_field", "//score/mw/com/impl/plumbing:field", "//score/mw/com/impl/plumbing:sample_allocatee_ptr", - "//score/mw/com/impl/methods:method_signature_element_ptr", "@score_baselibs//score/language/futurecpp", "@score_baselibs//score/result", "@score_logging//score/mw/log", diff --git a/score/mw/com/impl/skeleton_base_test.cpp b/score/mw/com/impl/skeleton_base_test.cpp index af6cbf069..abe542edf 100644 --- a/score/mw/com/impl/skeleton_base_test.cpp +++ b/score/mw/com/impl/skeleton_base_test.cpp @@ -667,6 +667,11 @@ class DummyField : public SkeletonFieldBase { return ResultBlank{}; }; + + bool IsSetHandlerRegistered() const noexcept override + { + return false; + } }; const auto kServiceIdentifier = make_ServiceIdentifierType("foo", 13, 37); const LolaServiceInstanceId kLolaInstanceId{23U}; diff --git a/score/mw/com/impl/skeleton_event.h b/score/mw/com/impl/skeleton_event.h index f5f768e1c..1a9245e89 100644 --- a/score/mw/com/impl/skeleton_event.h +++ b/score/mw/com/impl/skeleton_event.h @@ -36,9 +36,7 @@ namespace score::mw::com::impl // False Positive: this is a normal forward declaration. // coverity[autosar_cpp14_m3_2_3_violation] -template +template class SkeletonField; template @@ -237,7 +235,7 @@ ResultBlank SkeletonEvent::Send(const EventType& sample_value) n if (!send_result.has_value()) { score::mw::log::LogError("lola") << "SkeletonEvent::Send with copy failed: " << send_result.error().Message() - << ": " << send_result.error().UserMessage(); + << ": " << send_result.error().UserMessage(); return MakeUnexpected(ComErrc::kBindingFailure); } return send_result; @@ -265,7 +263,7 @@ ResultBlank SkeletonEvent::Send(SampleAllocateePtr sa if (!send_result.has_value()) { score::mw::log::LogError("lola") << "SkeletonEvent::Send zero copy failed: " << send_result.error().Message() - << ": " << send_result.error().UserMessage(); + << ": " << send_result.error().UserMessage(); return MakeUnexpected(ComErrc::kBindingFailure); } return send_result; @@ -290,7 +288,7 @@ Result> SkeletonEvent::Alloca if (!allocate_result.has_value()) { score::mw::log::LogError("lola") << "SkeletonEvent::Allocate failed: " << allocate_result.error().Message() - << ": " << allocate_result.error().UserMessage(); + << ": " << allocate_result.error().UserMessage(); return MakeUnexpected(ComErrc::kBindingFailure); } return allocate_result; @@ -300,7 +298,8 @@ template auto SkeletonEvent::GetTypedEventBinding() const noexcept -> SkeletonEventBinding* { auto* const typed_binding = dynamic_cast*>(binding_.get()); - SCORE_LANGUAGE_FUTURECPP_ASSERT_PRD_MESSAGE(typed_binding != nullptr, "Downcast to SkeletonEventBinding failed!"); + SCORE_LANGUAGE_FUTURECPP_ASSERT_PRD_MESSAGE(typed_binding != nullptr, + "Downcast to SkeletonEventBinding failed!"); return typed_binding; } diff --git a/score/mw/com/impl/skeleton_field.h b/score/mw/com/impl/skeleton_field.h index 7be228b0b..f8e80ae6c 100644 --- a/score/mw/com/impl/skeleton_field.h +++ b/score/mw/com/impl/skeleton_field.h @@ -13,11 +13,11 @@ #ifndef SCORE_MW_COM_IMPL_SKELETON_FIELD_H #define SCORE_MW_COM_IMPL_SKELETON_FIELD_H +#include "score/mw/com/impl/methods/skeleton_method.h" #include "score/mw/com/impl/plumbing/sample_allocatee_ptr.h" #include "score/mw/com/impl/plumbing/skeleton_field_binding_factory.h" #include "score/mw/com/impl/skeleton_event.h" #include "score/mw/com/impl/skeleton_field_base.h" -#include "score/mw/com/impl/methods/skeleton_method.h" #include "score/mw/com/impl/mocking/i_skeleton_field.h" @@ -45,9 +45,7 @@ struct EnableNeitherTag }; } // namespace detail -template +template class SkeletonField : public SkeletonFieldBase { public: @@ -126,17 +124,17 @@ class SkeletonField : public SkeletonFieldBase } // SFINAE-gated: only exists when EnableSet == true - template ::type = 0> - ResultBlank RegisterSetHandler(SetHandlerType handler) { - auto wrapped_callback = [this, user_callback = std::move(handler)] - (FieldType new_value) -> Result { + template ::type = 0> + ResultBlank RegisterSetHandler(SetHandlerType handler) + { + auto wrapped_callback = [this, user_callback = std::move(handler)](FieldType new_value) -> Result { // Allow user to validate/modify the value in-place user_callback(new_value); // Store the (possibly modified) value as the latest field value auto update_result = this->Update(new_value); - if (!update_result.has_value()) { + if (!update_result.has_value()) + { return MakeUnexpected(update_result.error()); } @@ -206,18 +204,17 @@ template SkeletonField::SkeletonField(SkeletonBase& parent, const std::string_view field_name, detail::EnableSetOnlyTag) - : SkeletonField{parent, - std::make_unique>( - parent, - field_name, - SkeletonFieldBindingFactory::CreateEventBinding( - SkeletonBaseView{parent}.GetAssociatedInstanceIdentifier(), - parent, - field_name), - typename SkeletonEvent::FieldOnlyConstructorEnabler{}), - std::make_unique(FieldType)>>( - parent, std::string(field_name) + "_Set"), - field_name} + : SkeletonField{ + parent, + std::make_unique>(parent, + field_name, + SkeletonFieldBindingFactory::CreateEventBinding( + SkeletonBaseView{parent}.GetAssociatedInstanceIdentifier(), + parent, + field_name), + typename SkeletonEvent::FieldOnlyConstructorEnabler{}), + std::make_unique(FieldType)>>(parent, std::string(field_name) + "_Set"), + field_name} { } @@ -227,24 +224,25 @@ template SkeletonField::SkeletonField(SkeletonBase& parent, const std::string_view field_name, detail::EnableNeitherTag) - : SkeletonField{parent, - std::make_unique>( - parent, - field_name, - SkeletonFieldBindingFactory::CreateEventBinding( - SkeletonBaseView{parent}.GetAssociatedInstanceIdentifier(), - parent, - field_name), - typename SkeletonEvent::FieldOnlyConstructorEnabler{}), - field_name} + : SkeletonField{ + parent, + std::make_unique>(parent, + field_name, + SkeletonFieldBindingFactory::CreateEventBinding( + SkeletonBaseView{parent}.GetAssociatedInstanceIdentifier(), + parent, + field_name), + typename SkeletonEvent::FieldOnlyConstructorEnabler{}), + field_name} { } /// \brief Testing ctor: binding is provided directly (used with mock bindings in tests). template -SkeletonField::SkeletonField(SkeletonBase& skeleton_base, - const std::string_view field_name, - std::unique_ptr> binding) +SkeletonField::SkeletonField( + SkeletonBase& skeleton_base, + const std::string_view field_name, + std::unique_ptr> binding) : SkeletonField{skeleton_base, std::make_unique>(skeleton_base, field_name, std::move(binding)), field_name} @@ -303,7 +301,8 @@ SkeletonField::SkeletonField(Skeleton } template -auto SkeletonField::operator=(SkeletonField&& other) & noexcept -> SkeletonField& +auto SkeletonField::operator=(SkeletonField&& other) & noexcept + -> SkeletonField& { if (this != &other) { @@ -346,7 +345,8 @@ ResultBlank SkeletonField::Update(con /// \brief FieldType is previously allocated by middleware and provided by the user to indicate that he is finished /// filling the provided pointer with live data. Dispatches to SkeletonEvent::Send() template -ResultBlank SkeletonField::Update(SampleAllocateePtr sample) noexcept +ResultBlank SkeletonField::Update( + SampleAllocateePtr sample) noexcept { if (skeleton_field_mock_ != nullptr) { @@ -372,8 +372,9 @@ Result> SkeletonFieldAllocate(); @@ -386,8 +387,9 @@ template // coverity[autosar_cpp14_a0_1_3_violation : FALSE] ResultBlank SkeletonField::DoDeferredUpdate() noexcept { - SCORE_LANGUAGE_FUTURECPP_ASSERT_MESSAGE(initial_field_value_ != nullptr, - "Initial field value containing a value is a precondition for DoDeferredUpdate."); + SCORE_LANGUAGE_FUTURECPP_ASSERT_MESSAGE( + initial_field_value_ != nullptr, + "Initial field value containing a value is a precondition for DoDeferredUpdate."); const auto update_result = UpdateImpl(*initial_field_value_); if (!update_result.has_value()) { @@ -406,7 +408,8 @@ ResultBlank SkeletonField::UpdateImpl } template -auto SkeletonField::GetTypedEvent() const noexcept -> SkeletonEvent* +auto SkeletonField::GetTypedEvent() const noexcept + -> SkeletonEvent* { auto* const typed_event = dynamic_cast*>(skeleton_event_dispatch_.get()); SCORE_LANGUAGE_FUTURECPP_ASSERT_PRD_MESSAGE(typed_event != nullptr, "Downcast to SkeletonEvent failed!"); diff --git a/score/mw/com/impl/skeleton_field_base.h b/score/mw/com/impl/skeleton_field_base.h index e1762cf8b..b481c7a37 100644 --- a/score/mw/com/impl/skeleton_field_base.h +++ b/score/mw/com/impl/skeleton_field_base.h @@ -14,8 +14,8 @@ #define SCORE_MW_COM_IMPL_SKELETON_FIELD_BASE_H #include "score/mw/com/impl/com_error.h" -#include "score/mw/com/impl/skeleton_event_base.h" #include "score/mw/com/impl/methods/skeleton_method_base.h" +#include "score/mw/com/impl/skeleton_event_base.h" #include "score/mw/log/logging.h" #include "score/result/result.h" @@ -66,7 +66,8 @@ class SkeletonFieldBase // a set handler before calling OfferService(), otherwise Offer() shall fail. if (!IsSetHandlerRegistered()) { - score::mw::log::LogWarn("lola") << "Set handler must be registered before offering field: "<< field_name_; + score::mw::log::LogWarn("lola") + << "Set handler must be registered before offering field: " << field_name_; return MakeUnexpected(ComErrc::kSetHandlerNotSet); } diff --git a/score/mw/com/impl/skeleton_field_base_test.cpp b/score/mw/com/impl/skeleton_field_base_test.cpp index 93ac7bfac..229cb01af 100644 --- a/score/mw/com/impl/skeleton_field_base_test.cpp +++ b/score/mw/com/impl/skeleton_field_base_test.cpp @@ -83,6 +83,11 @@ class MyDummyField : public SkeletonFieldBase return {}; } + bool IsSetHandlerRegistered() const noexcept override + { + return true; + } + bool was_deferred_update_called_{false}; bool is_initial_value_saved_{true}; }; @@ -94,6 +99,11 @@ class MyDummyFieldFailingDeferredUpdate final : public MyDummyField { return MakeUnexpected(ComErrc::kCommunicationLinkError); } + + bool IsSetHandlerRegistered() const noexcept override + { + return true; + } }; class SkeletonFieldBaseFixture : public ::testing::Test diff --git a/score/mw/com/impl/tracing/skeleton_tracing_test.cpp b/score/mw/com/impl/tracing/skeleton_tracing_test.cpp index 2947995c8..ac38df911 100644 --- a/score/mw/com/impl/tracing/skeleton_tracing_test.cpp +++ b/score/mw/com/impl/tracing/skeleton_tracing_test.cpp @@ -76,6 +76,11 @@ class MyDummyField : public SkeletonFieldBase { return {}; } + + bool IsSetHandlerRegistered() const noexcept override + { + return true; + } }; class SkeletonTracingFixture : public ::testing::Test diff --git a/score/mw/com/impl/traits.h b/score/mw/com/impl/traits.h index 29a5a708e..5727d3111 100644 --- a/score/mw/com/impl/traits.h +++ b/score/mw/com/impl/traits.h @@ -215,8 +215,9 @@ class SkeletonWrapperClass : public Interface SkeletonWrapperClass skeleton_wrapper(instance_identifier, std::move(skeleton_binding)); if (!skeleton_wrapper.AreBindingsValid()) { - ::score::mw::log::LogError("lola") << "Could not create SkeletonWrapperClass as Skeleton binding or service " - "element bindings could not be created."; + ::score::mw::log::LogError("lola") + << "Could not create SkeletonWrapperClass as Skeleton binding or service " + "element bindings could not be created."; return MakeUnexpected(ComErrc::kBindingFailure); } @@ -267,8 +268,10 @@ class SkeletonWrapperClass : public Interface std::unordered_map>> instance_identifier_creation_results) { - score::cpp::ignore = instance_specifier_creation_results_.emplace(std::move(instance_specifier_creation_results)); - score::cpp::ignore = instance_identifier_creation_results_.emplace(std::move(instance_identifier_creation_results)); + score::cpp::ignore = + instance_specifier_creation_results_.emplace(std::move(instance_specifier_creation_results)); + score::cpp::ignore = + instance_identifier_creation_results_.emplace(std::move(instance_identifier_creation_results)); } static void ClearCreationResults()