Matter SDK Coverage Report
Current view: top level - app/server-cluster - ServerClusterInterfaceRegistry.h (source / functions) Coverage Total Hit
Test: SHA:f1767a8b0a3778fdf31b1d979afbdf544892fd94 Lines: 95.6 % 45 43
Test Date: 2026-06-03 07:35:21 Functions: 100.0 % 68 68

            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/AppConfig.h>
      20              : #include <app/ConcreteClusterPath.h>
      21              : #include <app/server-cluster/ServerClusterInterface.h>
      22              : #include <lib/core/CHIPError.h>
      23              : #include <lib/core/DataModelTypes.h>
      24              : #include <lib/support/logging/CHIPLogging.h>
      25              : 
      26              : #include <cstdint>
      27              : #include <new>
      28              : #include <optional>
      29              : 
      30              : namespace chip {
      31              : namespace app {
      32              : 
      33              : /// Represents an entry in the server cluster interface registry for
      34              : /// a specific interface.
      35              : ///
      36              : /// In practice this is a single-linked list element.
      37              : struct ServerClusterRegistration
      38              : {
      39              :     // A single-linked list of clusters registered for the given `endpointId`
      40              :     ServerClusterInterface * const serverClusterInterface;
      41              :     ServerClusterRegistration * next;
      42              : 
      43          493 :     constexpr ServerClusterRegistration(ServerClusterInterface & interface, ServerClusterRegistration * next_item = nullptr) :
      44          493 :         serverClusterInterface(&interface), next(next_item)
      45          493 :     {}
      46              :     ServerClusterRegistration(ServerClusterRegistration && other) = default;
      47              : 
      48              :     // we generally do not want to allow copies as those may have different "next" entries.
      49              :     ServerClusterRegistration(const ServerClusterRegistration & other)             = delete;
      50              :     ServerClusterRegistration & operator=(const ServerClusterRegistration & other) = delete;
      51              : };
      52              : 
      53              : /// It is very typical to join together a registration and a Server
      54              : /// This templates makes this registration somewhat easier/standardized.
      55              : template <typename SERVER_CLUSTER>
      56              : struct RegisteredServerCluster
      57              : {
      58              :     template <typename... Args>
      59           26 :     RegisteredServerCluster(Args &&... args) : cluster(std::forward<Args>(args)...), registration(cluster)
      60           26 :     {}
      61              : 
      62           26 :     [[nodiscard]] constexpr ServerClusterRegistration & Registration() { return registration; }
      63              :     [[nodiscard]] constexpr const ServerClusterRegistration & Registration() const { return registration; }
      64              : 
      65           71 :     [[nodiscard]] constexpr SERVER_CLUSTER & Cluster() { return cluster; }
      66           30 :     [[nodiscard]] constexpr const SERVER_CLUSTER & Cluster() const { return cluster; }
      67              : 
      68              : private:
      69              :     SERVER_CLUSTER cluster;
      70              :     ServerClusterRegistration registration;
      71              : };
      72              : 
      73              : /// Lazy-construction of a RegisteredServerCluster to allow at-runtime lifetime management
      74              : ///
      75              : /// If using this class, manamement of Create/Destroy MUST be done correctly.
      76              : template <typename SERVER_CLUSTER>
      77              : struct LazyRegisteredServerCluster
      78              : {
      79              : public:
      80           10 :     constexpr LazyRegisteredServerCluster() = default;
      81           11 :     ~LazyRegisteredServerCluster()
      82              :     {
      83           11 :         if (IsConstructed())
      84              :         {
      85            4 :             Destroy();
      86              :         }
      87           11 :     }
      88              : 
      89           11 :     void Destroy()
      90              :     {
      91           11 :         if (!IsConstructed())
      92              :         {
      93              :             // Should not happen — Init/Shutdown are paired at the CodegenDataModelProvider level.
      94              : #if CHIP_CONFIG_ENABLE_SERVER_RESTART_SUPPORT
      95            0 :             ChipLogError(AppServer, "Destroy() called on already-destroyed cluster — this should not happen");
      96              : #else
      97              :             chipDie();
      98              : #endif
      99            0 :             return;
     100              :         }
     101           11 :         Registration().~ServerClusterRegistration();
     102           11 :         memset(mRegistration, 0, sizeof(mRegistration));
     103              : 
     104           11 :         Cluster().~SERVER_CLUSTER();
     105           11 :         memset(mCluster, 0, sizeof(mCluster));
     106              :     }
     107              : 
     108              :     template <typename... Args>
     109           11 :     void Create(Args &&... args)
     110              :     {
     111           11 :         VerifyOrDie(!IsConstructed());
     112              : 
     113           11 :         new (mCluster) SERVER_CLUSTER(std::forward<Args>(args)...);
     114           11 :         new (mRegistration) ServerClusterRegistration(Cluster());
     115           11 :     }
     116              : 
     117           79 :     [[nodiscard]] constexpr bool IsConstructed() const
     118              :     {
     119              :         // mRegistration is supposed to containt a serverClusterInterface that is NOT null
     120              :         // so we check for non-zero content. This relies that nullptr is 0
     121           79 :         return Registration().serverClusterInterface != nullptr;
     122              :     }
     123              : 
     124           22 :     [[nodiscard]] constexpr ServerClusterRegistration & Registration()
     125              :     {
     126           22 :         return *std::launder(reinterpret_cast<ServerClusterRegistration *>(mRegistration));
     127              :     }
     128              : 
     129           79 :     [[nodiscard]] constexpr const ServerClusterRegistration & Registration() const
     130              :     {
     131           79 :         return *std::launder(reinterpret_cast<const ServerClusterRegistration *>(mRegistration));
     132              :     }
     133              : 
     134           50 :     [[nodiscard]] constexpr SERVER_CLUSTER & Cluster() { return *std::launder(reinterpret_cast<SERVER_CLUSTER *>(mCluster)); }
     135              : 
     136            4 :     [[nodiscard]] constexpr const SERVER_CLUSTER & Cluster() const
     137              :     {
     138            4 :         return *std::launder(reinterpret_cast<const SERVER_CLUSTER *>(mCluster));
     139              :     }
     140              : 
     141              : private:
     142              :     alignas(SERVER_CLUSTER) uint8_t mCluster[sizeof(SERVER_CLUSTER)]                            = { 0 };
     143              :     alignas(ServerClusterRegistration) uint8_t mRegistration[sizeof(ServerClusterRegistration)] = { 0 };
     144              : };
     145              : 
     146              : /// Allows registering and retrieving ServerClusterInterface instances for specific cluster paths.
     147              : class ServerClusterInterfaceRegistry
     148              : {
     149              : public:
     150              :     ~ServerClusterInterfaceRegistry();
     151              : 
     152              :     /// Add the given entry to the registry.
     153              :     ///
     154              :     /// Requirements:
     155              :     ///   - entry MUST NOT be part of any other registration
     156              :     ///   - LIFETIME of entry must outlive the Registry (or entry must be unregistered)
     157              :     ///
     158              :     /// There can be only a single registration for a given `endpointId/clusterId` path.
     159              :     [[nodiscard]] CHIP_ERROR Register(ServerClusterRegistration & entry);
     160              : 
     161              :     /// Remove an existing registration
     162              :     ///
     163              :     /// Will return CHIP_ERROR_NOT_FOUND if the given registration is not found.
     164              :     CHIP_ERROR Unregister(ServerClusterInterface *,
     165              :                           ClusterShutdownType clusterShutdownType = ClusterShutdownType::kClusterShutdown);
     166              : 
     167              :     /// Return the interface registered for the given cluster path or nullptr if one does not exist
     168              :     ServerClusterInterface * Get(const ConcreteClusterPath & path);
     169              : 
     170              :     // Set up the underlying context for all clusters that are managed by this registry.
     171              :     //
     172              :     // The values within context will be moved and used as-is.
     173              :     //
     174              :     // Returns:
     175              :     //   - CHIP_NO_ERROR on success
     176              :     //   - CHIP_ERROR_HAD_FAILURES if some cluster `Startup` calls had errors (Startup
     177              :     //     will be called for all clusters).
     178              :     CHIP_ERROR SetContext(ServerClusterContext && context);
     179              : 
     180              :     // Invalidates current context.
     181              :     void ClearContext();
     182              : 
     183              :     // Represents an iterable list of all clusters registered in this registry.
     184              :     // The list is only valid as long as the registry is not modified.
     185              :     // The list is not guaranteed to be in any particular order.
     186              :     class ServerClusterInstances
     187              :     {
     188              :     public:
     189              :         class Iterator
     190              :         {
     191              :         public:
     192          438 :             Iterator(ServerClusterRegistration * registration) : mRegistration(registration) {}
     193              : 
     194           75 :             Iterator & operator++()
     195              :             {
     196           75 :                 if (mRegistration)
     197              :                 {
     198           75 :                     mRegistration = mRegistration->next;
     199              :                 }
     200           75 :                 return *this;
     201              :             }
     202              :             bool operator==(const Iterator & other) const { return mRegistration == other.mRegistration; }
     203          283 :             bool operator!=(const Iterator & other) const { return mRegistration != other.mRegistration; }
     204           97 :             ServerClusterInterface * operator*() { return mRegistration ? mRegistration->serverClusterInterface : nullptr; }
     205              : 
     206              :         private:
     207              :             ServerClusterRegistration * mRegistration;
     208              :         };
     209              : 
     210          300 :         constexpr ServerClusterInstances(ServerClusterRegistration * start) : mStart(start) {}
     211          230 :         Iterator begin() { return { mStart }; }
     212          208 :         Iterator end() { return { nullptr }; }
     213              : 
     214              :     private:
     215              :         ServerClusterRegistration * mStart;
     216              :     };
     217              : 
     218              :     ServerClusterInstances AllServerClusterInstances();
     219              : 
     220              : protected:
     221              :     ServerClusterRegistration * mRegistrations = nullptr;
     222              : 
     223              :     // A one-element cache to speed up finding a cluster within an endpoint.
     224              :     // The endpointId specifies which endpoint the cache belongs to.
     225              :     ServerClusterInterface * mCachedInterface = nullptr;
     226              : 
     227              :     // Managing context for this registry
     228              :     std::optional<ServerClusterContext> mContext;
     229              : };
     230              : 
     231              : } // namespace app
     232              : } // namespace chip
        

Generated by: LCOV version 2.0-1