Line data Source code
1 : /*
2 : * Copyright (c) 2025 Project CHIP Authors
3 : * All rights reserved.
4 : *
5 : * Licensed under the Apache License, Version 2.0 (the "License");
6 : * you may not use this file except in compliance with the License.
7 : * You may obtain a copy of the License at
8 : *
9 : * http://www.apache.org/licenses/LICENSE-2.0
10 : *
11 : * Unless required by applicable law or agreed to in writing, software
12 : * distributed under the License is distributed on an "AS IS" BASIS,
13 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 : * See the License for the specific language governing permissions and
15 : * limitations under the License.
16 : */
17 : #pragma once
18 :
19 : #include <app/ConcreteClusterPath.h>
20 : #include <app/server-cluster/ServerClusterInterface.h>
21 : #include <lib/core/CHIPError.h>
22 : #include <lib/core/DataModelTypes.h>
23 :
24 : #include <iterator>
25 :
26 : namespace chip {
27 : namespace app {
28 :
29 : /// Represents an entry in the server cluster interface registry for
30 : /// a specific interface.
31 : ///
32 : /// In practice this is a single-linked list element.
33 : struct ServerClusterRegistration
34 : {
35 : // A single-linked list of clusters registered for the given `endpointId`
36 : ServerClusterInterface * const serverClusterInterface;
37 : ServerClusterRegistration * next;
38 :
39 : constexpr ServerClusterRegistration(ServerClusterInterface & interface, ServerClusterRegistration * next_item = nullptr) :
40 : serverClusterInterface(&interface), next(next_item)
41 : {}
42 : ServerClusterRegistration(ServerClusterRegistration && other) = default;
43 :
44 : // we generally do not want to allow copies as those may have different "next" entries.
45 : ServerClusterRegistration(const ServerClusterRegistration & other) = delete;
46 : ServerClusterRegistration & operator=(const ServerClusterRegistration & other) = delete;
47 : };
48 :
49 : /// Allows registering and retrieving ServerClusterInterface instances for specific cluster paths.
50 : class ServerClusterInterfaceRegistry
51 : {
52 : public:
53 : /// represents an iterable list of clusters
54 : class ClustersList
55 : {
56 : public:
57 : class Iterator
58 : {
59 : public:
60 : using difference_type = size_t;
61 : using value_type = ServerClusterInterface *;
62 : using pointer = ServerClusterInterface **;
63 : using reference = ServerClusterInterface *&;
64 : using iterator_category = std::forward_iterator_tag;
65 :
66 33802 : Iterator(ServerClusterRegistration * interface, EndpointId endpoint) : mRegistration(interface), mEndpointId(endpoint)
67 : {
68 33802 : AdvanceUntilMatchingEndpoint();
69 33802 : }
70 :
71 202 : Iterator & operator++()
72 : {
73 202 : if (mRegistration != nullptr)
74 : {
75 202 : mRegistration = mRegistration->next;
76 : }
77 202 : AdvanceUntilMatchingEndpoint();
78 202 : return *this;
79 : }
80 : bool operator==(const Iterator & other) const { return mRegistration == other.mRegistration; }
81 17102 : bool operator!=(const Iterator & other) const { return mRegistration != other.mRegistration; }
82 202 : ServerClusterInterface * operator*() { return mRegistration->serverClusterInterface; }
83 :
84 : private:
85 : ServerClusterRegistration * mRegistration;
86 : EndpointId mEndpointId;
87 :
88 34004 : void AdvanceUntilMatchingEndpoint()
89 : {
90 36004 : while ((mRegistration != nullptr) && (mRegistration->serverClusterInterface->GetPath().mEndpointId != mEndpointId))
91 : {
92 2000 : mRegistration = mRegistration->next;
93 : }
94 34004 : }
95 : };
96 :
97 16901 : constexpr ClustersList(ServerClusterRegistration * start, EndpointId endpointId) : mStart(start), mEndpointId(endpointId) {}
98 16901 : Iterator begin() { return { mStart, mEndpointId }; }
99 16901 : Iterator end() { return { nullptr, mEndpointId }; }
100 :
101 : private:
102 : ServerClusterRegistration * mStart;
103 : EndpointId mEndpointId;
104 : };
105 :
106 : ~ServerClusterInterfaceRegistry();
107 :
108 : /// Add the given entry to the registry.
109 : ///
110 : /// Requirements:
111 : /// - entry MUST NOT be part of any other registration
112 : /// - LIFETIME of entry must outlive the Registry (or entry must be unregistered)
113 : ///
114 : /// There can be only a single registration for a given `endpointId/clusterId` path.
115 : [[nodiscard]] CHIP_ERROR Register(ServerClusterRegistration & entry);
116 :
117 : /// Remove an existing registration for a given endpoint/cluster path.
118 : ///
119 : /// Returns the previous registration if any exists (or nullptr if nothing
120 : /// to unregister)
121 : ServerClusterInterface * Unregister(const ConcreteClusterPath & path);
122 :
123 : /// Return the interface registered for the given cluster path or nullptr if one does not exist
124 : ServerClusterInterface * Get(const ConcreteClusterPath & path);
125 :
126 : /// Provides a list of clusters that are registered for the given endpoint.
127 : ///
128 : /// ClustersList points inside the internal registrations of the registry, so
129 : /// the list is only valid as long as the registry is not modified.
130 : ClustersList ClustersOnEndpoint(EndpointId endpointId);
131 :
132 : /// Unregister all registrations for the given endpoint.
133 : void UnregisterAllFromEndpoint(EndpointId endpointId);
134 :
135 : // Set up the underlying context for all clusters that are managed by this registry.
136 : //
137 : // The values within context will be copied and used.
138 : CHIP_ERROR SetContext(ServerClusterContext && context);
139 :
140 : // Invalidates current context.
141 : void ClearContext();
142 :
143 : private:
144 : ServerClusterRegistration * mRegistrations = nullptr;
145 :
146 : // A one-element cache to speed up finding a cluster within an endpoint.
147 : // The endpointId specifies which endpoint the cache belongs to.
148 : ServerClusterInterface * mCachedInterface = nullptr;
149 :
150 : // Managing context for this registry
151 : std::optional<ServerClusterContext> mContext;
152 : };
153 :
154 : } // namespace app
155 : } // namespace chip
|