Matter SDK Coverage Report
Current view: top level - data-model-providers/codegen - ServerClusterInterfaceRegistry.h (source / functions) Coverage Total Hit
Test: SHA:3dd9280bcb8aa1ee9d6fd914e93404039e6ed7a0 Lines: 100.0 % 25 25
Test Date: 2025-07-12 07:13:33 Functions: 100.0 % 8 8

            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 <cstdint>
      25              : #include <new>
      26              : 
      27              : namespace chip {
      28              : namespace app {
      29              : 
      30              : /// Represents an entry in the server cluster interface registry for
      31              : /// a specific interface.
      32              : ///
      33              : /// In practice this is a single-linked list element.
      34              : struct ServerClusterRegistration
      35              : {
      36              :     // A single-linked list of clusters registered for the given `endpointId`
      37              :     ServerClusterInterface * const serverClusterInterface;
      38              :     ServerClusterRegistration * next;
      39              : 
      40              :     constexpr ServerClusterRegistration(ServerClusterInterface & interface, ServerClusterRegistration * next_item = nullptr) :
      41              :         serverClusterInterface(&interface), next(next_item)
      42              :     {}
      43              :     ServerClusterRegistration(ServerClusterRegistration && other) = default;
      44              : 
      45              :     // we generally do not want to allow copies as those may have different "next" entries.
      46              :     ServerClusterRegistration(const ServerClusterRegistration & other)             = delete;
      47              :     ServerClusterRegistration & operator=(const ServerClusterRegistration & other) = delete;
      48              : };
      49              : 
      50              : /// It is very typical to join together a registration and a Server
      51              : /// This templates makes this registration somewhat easier/standardized.
      52              : template <typename SERVER_CLUSTER>
      53              : struct RegisteredServerCluster
      54              : {
      55              :     template <typename... Args>
      56              :     RegisteredServerCluster(Args &&... args) : cluster(std::forward<Args>(args)...), registration(cluster)
      57              :     {}
      58              : 
      59              :     [[nodiscard]] constexpr ServerClusterRegistration & Registration() { return registration; }
      60              :     [[nodiscard]] constexpr SERVER_CLUSTER & Cluster() { return cluster; }
      61              : 
      62              : private:
      63              :     SERVER_CLUSTER cluster;
      64              :     ServerClusterRegistration registration;
      65              : };
      66              : 
      67              : /// Lazy-construction of a RegisteredServerCluster to allow at-runtime lifetime management
      68              : ///
      69              : /// If using this class, manamement of Create/Destroy MUST be done correctly.
      70              : template <typename SERVER_CLUSTER>
      71              : struct LazyRegisteredServerCluster
      72              : {
      73              : public:
      74              :     constexpr LazyRegisteredServerCluster() = default;
      75              :     ~LazyRegisteredServerCluster()
      76              :     {
      77              :         if (IsConstructed())
      78              :         {
      79              :             Destroy();
      80              :         }
      81              :     }
      82              : 
      83              :     void Destroy()
      84              :     {
      85              :         VerifyOrDie(IsConstructed());
      86              :         Registration().~ServerClusterRegistration();
      87              :         memset(mRegistration, 0, sizeof(mRegistration));
      88              : 
      89              :         Cluster().~SERVER_CLUSTER();
      90              :         memset(mCluster, 0, sizeof(mCluster));
      91              :     }
      92              : 
      93              :     template <typename... Args>
      94              :     void Create(Args &&... args)
      95              :     {
      96              :         VerifyOrDie(!IsConstructed());
      97              : 
      98              :         new (mCluster) SERVER_CLUSTER(std::forward<Args>(args)...);
      99              :         new (mRegistration) ServerClusterRegistration(Cluster());
     100              :     }
     101              : 
     102              :     [[nodiscard]] constexpr bool IsConstructed() const
     103              :     {
     104              :         // mRegistration is supposed to containt a serverClusterInterface that is NOT null
     105              :         // so we check for non-zero content. This relies that nullptr is 0
     106              :         return Registration().serverClusterInterface != nullptr;
     107              :     }
     108              : 
     109              :     [[nodiscard]] constexpr ServerClusterRegistration & Registration()
     110              :     {
     111              :         return *std::launder(reinterpret_cast<ServerClusterRegistration *>(mRegistration));
     112              :     }
     113              : 
     114              :     [[nodiscard]] constexpr const ServerClusterRegistration & Registration() const
     115              :     {
     116              :         return *std::launder(reinterpret_cast<const ServerClusterRegistration *>(mRegistration));
     117              :     }
     118              : 
     119              :     [[nodiscard]] constexpr SERVER_CLUSTER & Cluster() { return *std::launder(reinterpret_cast<SERVER_CLUSTER *>(mCluster)); }
     120              : 
     121              :     [[nodiscard]] constexpr const SERVER_CLUSTER & Cluster() const
     122              :     {
     123              :         return *std::launder(reinterpret_cast<const SERVER_CLUSTER *>(mCluster));
     124              :     }
     125              : 
     126              : private:
     127              :     alignas(SERVER_CLUSTER) uint8_t mCluster[sizeof(SERVER_CLUSTER)]                            = { 0 };
     128              :     alignas(ServerClusterRegistration) uint8_t mRegistration[sizeof(ServerClusterRegistration)] = { 0 };
     129              : };
     130              : 
     131              : /// Allows registering and retrieving ServerClusterInterface instances for specific cluster paths.
     132              : class ServerClusterInterfaceRegistry
     133              : {
     134              : public:
     135              :     /// represents an iterable list of clusters
     136              :     class ClustersList
     137              :     {
     138              :     public:
     139              :         class Iterator
     140              :         {
     141              :         public:
     142        33912 :             Iterator(ServerClusterRegistration * interface, EndpointId endpoint) : mEndpointId(endpoint), mRegistration(interface)
     143              :             {
     144        33912 :                 if (mRegistration != nullptr)
     145              :                 {
     146           14 :                     mSpan = interface->serverClusterInterface->GetPaths();
     147              :                 }
     148        33912 :                 AdvanceUntilMatchingEndpoint();
     149        33912 :             }
     150              : 
     151          206 :             Iterator & operator++()
     152              :             {
     153          206 :                 if (!mSpan.empty())
     154              :                 {
     155          206 :                     mSpan = mSpan.SubSpan(1);
     156              :                 }
     157          206 :                 AdvanceUntilMatchingEndpoint();
     158          206 :                 return *this;
     159              :             }
     160              :             bool operator==(const Iterator & other) const { return mRegistration == other.mRegistration; }
     161        17158 :             bool operator!=(const Iterator & other) const { return mRegistration != other.mRegistration; }
     162          206 :             ClusterId operator*() { return mSpan.begin()->mClusterId; }
     163              : 
     164              :         private:
     165              :             const EndpointId mEndpointId;
     166              :             ServerClusterRegistration * mRegistration;
     167              :             Span<const ConcreteClusterPath> mSpan;
     168              : 
     169        34118 :             void AdvanceUntilMatchingEndpoint()
     170              :             {
     171        38321 :                 while (mRegistration != nullptr)
     172              :                 {
     173         4409 :                     if (mSpan.empty())
     174              :                     {
     175         2203 :                         mRegistration = mRegistration->next;
     176         2203 :                         if (mRegistration != nullptr)
     177              :                         {
     178         2189 :                             mSpan = mRegistration->serverClusterInterface->GetPaths();
     179              :                         }
     180         2203 :                         continue;
     181              :                     }
     182         2206 :                     if (mSpan.begin()->mEndpointId == mEndpointId)
     183              :                     {
     184          206 :                         return;
     185              :                     }
     186              : 
     187              :                     // need to keep searching
     188         2000 :                     mSpan = mSpan.SubSpan(1);
     189              :                 }
     190              :             }
     191              :         };
     192              : 
     193        16954 :         constexpr ClustersList(ServerClusterRegistration * start, EndpointId endpointId) : mEndpointId(endpointId), mStart(start) {}
     194        16954 :         Iterator begin() { return { mStart, mEndpointId }; }
     195        16958 :         Iterator end() { return { nullptr, mEndpointId }; }
     196              : 
     197              :     private:
     198              :         const EndpointId mEndpointId;
     199              :         ServerClusterRegistration * mStart;
     200              :     };
     201              : 
     202              :     ~ServerClusterInterfaceRegistry();
     203              : 
     204              :     /// Add the given entry to the registry.
     205              :     /// NOTE the requirement of entries to be part of the same endpoint.
     206              :     ///
     207              :     /// Requirements:
     208              :     ///   - entry MUST NOT be part of any other registration
     209              :     ///   - paths MUST be part of the same endpoint (requirement for codegen server cluster interface implementations)
     210              :     ///
     211              :     ///   - LIFETIME of entry must outlive the Registry (or entry must be unregistered)
     212              :     ///
     213              :     /// There can be only a single registration for a given `endpointId/clusterId` path.
     214              :     [[nodiscard]] CHIP_ERROR Register(ServerClusterRegistration & entry);
     215              : 
     216              :     /// Remove an existing registration
     217              :     ///
     218              :     /// Will return CHIP_ERROR_NOT_FOUND if the given registration is not found.
     219              :     CHIP_ERROR Unregister(ServerClusterInterface *);
     220              : 
     221              :     /// Return the interface registered for the given cluster path or nullptr if one does not exist
     222              :     ServerClusterInterface * Get(const ConcreteClusterPath & path);
     223              : 
     224              :     /// Provides a list of clusters that are registered for the given endpoint.
     225              :     ///
     226              :     /// ClustersList points inside the internal registrations of the registry, so
     227              :     /// the list is only valid as long as the registry is not modified.
     228              :     ClustersList ClustersOnEndpoint(EndpointId endpointId);
     229              : 
     230              :     /// Unregister all registrations for the given endpoint.
     231              :     void UnregisterAllFromEndpoint(EndpointId endpointId);
     232              : 
     233              :     // Set up the underlying context for all clusters that are managed by this registry.
     234              :     //
     235              :     // The values within context will be copied and used.
     236              :     CHIP_ERROR SetContext(ServerClusterContext && context);
     237              : 
     238              :     // Invalidates current context.
     239              :     void ClearContext();
     240              : 
     241              : private:
     242              :     ServerClusterRegistration * mRegistrations = nullptr;
     243              : 
     244              :     // A one-element cache to speed up finding a cluster within an endpoint.
     245              :     // The endpointId specifies which endpoint the cache belongs to.
     246              :     ServerClusterInterface * mCachedInterface = nullptr;
     247              : 
     248              :     // Managing context for this registry
     249              :     std::optional<ServerClusterContext> mContext;
     250              : };
     251              : 
     252              : } // namespace app
     253              : } // namespace chip
        

Generated by: LCOV version 2.0-1