Skip to content

Add field tags#357

Open
KrishaDeshkool wants to merge 10 commits intoeclipse-score:mainfrom
KrishaDeshkool:add_field_tags
Open

Add field tags#357
KrishaDeshkool wants to merge 10 commits intoeclipse-score:mainfrom
KrishaDeshkool:add_field_tags

Conversation

@KrishaDeshkool
Copy link
Copy Markdown
Contributor

No description provided.

@KrishaDeshkool
Copy link
Copy Markdown
Contributor Author

Once the CI is green, i will make this PR open and can we reviewed.

@KrishaDeshkool KrishaDeshkool marked this pull request as ready for review April 27, 2026 09:40
@KrishaDeshkool KrishaDeshkool marked this pull request as draft April 28, 2026 07:34
Comment thread score/mw/com/impl/skeleton_field.h Outdated
Comment thread score/mw/com/impl/skeleton_field.h
@KrishaDeshkool KrishaDeshkool force-pushed the add_field_tags branch 7 times, most recently from e47f755 to a4a564f Compare May 4, 2026 14:18
/// ctors via the detail::WithTestTag marker, required as the 3rd argument. Bindings default to nullptr;
ProxyField(ProxyBase& proxy_base,
const std::string_view field_name,
detail::WithTestTag,
Copy link
Copy Markdown
Contributor Author

@KrishaDeshkool KrishaDeshkool May 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the topic i wanted to discuss,
if we do not have this Tag then if we make all other bindings as nullptr, in other words make these defaults,
then i have the following issue,
when all the bingngs are nullptr then the all of them are defaulted and depending on the tag combination , the real production ctr would clash with this test ctr and since the prod ctr is templated the compiler would pick this non templated ctr and hence we run into issues in production, this is why i have introduced this WithTestTag to clearly say this is test only ctr, i think it also reads much better than adding a comment on the ctr that this is a test only ctr.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See comment here: #357 (comment)

The new order allows us to set the bindings to nullptrs by default for
test only constructors. This will be useful for fields which will
require optionally inserting get / set bindings. We change all
constructors so that they're all consistent.
- Use a single test constructor which creates the get / set methods
  according to the provided bindings. This allows us to remove the
  test-only constructor overloads for each template arg combination.
- Always store the get / set method dispatches as unique_ptrs even if
  they're not enabled (when disabled, they'll simply be nullptrs). This
  allows us to have a single private constructor which always accepts
  unique_ptrs (which may be valid or nullptrs).
@KrishaDeshkool KrishaDeshkool force-pushed the add_field_tags branch 4 times, most recently from 50abfa1 to 879c9ce Compare May 5, 2026 09:29
Replaces the EnableGet/EnableSet/EnableNotifier bool template parameters
on ProxyField and SkeletonField with a variadic pack of tags (WithGetter,
WithSetter) declared in field_tags.h. Presence of a tag enables the
matching API. The notifier surface stays unconditional on both sides,
since a field without a notifier cannot propagate value changes.

Also updates friend/forward declarations in ProxyEvent, ProxyMethod,
SkeletonEvent and SkeletonMethod, the Trait::Field aliases plus the
traits example doc, and the skeleton_field_test.cpp call sites.
* Introducing a WithNotifier field tag
* When both getter and notification mechanism is turned off there is no way for the consumer to observe the field values.
 making this configuration a compile time failure.
@KrishaDeshkool KrishaDeshkool marked this pull request as ready for review May 5, 2026 09:32
Comment thread score/mw/com/impl/skeleton_field.h
Comment thread score/mw/com/impl/traits_test.cpp Outdated
.WillOnce(Return(ByMove(std::move(skeleton_field_binding_mock_ptr))));
// Field get method binding (not yet fully implemented; set method only exists when EnableSet=true)
// Field set method binding (only created when the SkeletonField is tagged WithSetter)
EXPECT_CALL(skeleton_method_binding_factory_mock_guard_.factory_mock_, Create(_, _, _, _))
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should be more concise here? You are expecting a call to Create with MethodType kSet? ... and eventually also test/make clear, what "method-name" we are expecting here? Hint - in this case the method-name is the field-name afaik ...

I guess - currently gtest is smart enough to correctly assign the EXPECT in line 553 vs line 559 by the arg kMethodName ...

@KrishaDeshkool KrishaDeshkool requested a review from crimson11 May 6, 2026 10:27
// parameters. The std::is_same<FieldType, ClassFieldType> line ties substitution to a function-template
// parameter so the check fires at overload resolution instead of class instantiation.
template <typename FieldType, typename ClassFieldType, typename TargetTag, typename... Tags>
struct is_tag_enabled : std::conjunction<contains_type<TargetTag, Tags...>, std::is_same<FieldType, ClassFieldType>>
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since is_tag_enabled is a public function to be used by other targets, it shouldn't be in the detail namespace.

// parameter so the check fires at overload resolution instead of class instantiation.
template <typename FieldType, typename ClassFieldType, typename TargetTag, typename... Tags>
struct is_tag_enabled : std::conjunction<contains_type<TargetTag, Tags...>, std::is_same<FieldType, ClassFieldType>>
{
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should have unit tests for any public function (so definitely is_tag_enabled and if contains_type is publicly exposed i.e. not in the detail namespace then also for it). You can look at the unit tests that I wrote for method_handler_checker_test as a reference if you want: https://github.com/eclipse-score/communication/pull/369/changes#diff-a5298ded87ed55bcf9aceb680edbe7e0c9b81700b7a5e0f24feb7b3600dac64d

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can only support "positive" tests for the moment, but you should also write the negative tests e.g.

Comment thread score/mw/com/impl/proxy_field.h Outdated
const bool EnableSet = false,
const bool EnableNotifier = false>
/// \tparam Tags Optional tag pack; presence of WithGetter / WithSetter enables Get() / Set() respectively.
/// The notifier surface (Subscribe, GetNewSamples, ...) is part of every field.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What does "surface" mean here?

const bool EnableNotifier = false>
/// \tparam Tags Optional tag pack; presence of WithGetter / WithSetter enables Get() / Set() respectively.
/// The notifier surface (Subscribe, GetNewSamples, ...) is part of every field.
template <typename SampleDataType, typename... Tags>
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe be explicit in the documentation that the supported tags are any combination of the tags defined in field_tags.h (i.e. WithGetter, WithSetter, WithNotifier)

Comment thread score/mw/com/impl/proxy_field.h Outdated
///
/// This is used for testing only. Allows for directly setting the bindings, and usually the mock binding is used
/// here.
/// Testing ctor: bindings are passed in directly (used with mock bindings).
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use the doxygen format.

/// \brief ...
///
/// More details here.

Comment thread score/mw/com/impl/proxy_field.h Outdated

/// Testing ctor: bindings are passed in directly (used with mock bindings).
/// Testing ctor: bindings are passed in directly (used with mock bindings). The event binding is required
/// (no default) to disambiguate this overload from the production ctors when called as `{proxy, field_name}`.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But there is a default agrument for event_binding?

Comment thread score/mw/com/impl/proxy_field.h Outdated
proxy_base,
field_name,
std::make_unique<ProxyEvent<FieldType>>(proxy_base, field_name, std::move(event_binding)),
// If a binding is not provided, then we don't create the method. This ensures that the ProxyMethod
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to document the seond sentence "This ensures that the ProxyMethod doesn't report that the binding is invalid (via proxy_base_view.MarkServiceElementBindingInvalid())" somewhere. Either here or in the docstring for the function.

static std::unique_ptr<ProxyMethod<FieldType()>> MakeGetMethodDispatchFromFactory(ProxyBase& proxy_base,
const std::string_view field_name)
{
if constexpr (kHasGetter)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it would be clearer to only call this function when a getter is enabled. I.e. the construtor either calls MakeGetMethodDispatchFromFactory or explicitly passes a nullptr. That way it's clear from the constructor whether a method dispatch is created or not.

On second thought, what could make more sense is to have one production constructor and the dispatch objects are created according to the tags in these "Make" functions. Because currently all those constructors do the same thing, i.e. simply dispatch to these functions. In this case, maybe you can rename them to MakeGetMethodDispatchIfUsed or MakeGetMethodDispatchIfEnabled or something.

using ProxyEventFieldMock = typename T::ProxyEventFieldMock;

ProxyEventFieldMockFixture()
: unit_{[this] {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this commit makes sense. I don't think we should add a tag for a test only "helper" constructor. I think we just live with the limitation that we have to always provide the event binding (either with a real binding or a nullptr).

.WillOnce(Return(ByMove(std::move(skeleton_field_binding_mock_ptr))));
// Field set method binding (only created when the SkeletonField is tagged WithSetter)
EXPECT_CALL(skeleton_method_binding_factory_mock_guard_.factory_mock_, Create(_, _, _, _))
// Field get method binding always created for every SkeletonField regardless of tags, because get_method_ is
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants