Matter SDK Coverage Report
Current view: top level - app/storage - FabricTableImpl.h (source / functions) Coverage Total Hit
Test: SHA:2a48c1efeab1c0f76f3adb3a0940b0f7de706453 Lines: 100.0 % 6 6
Test Date: 2026-01-31 08:14:20 Functions: 76.9 % 13 10

            Line data    Source code
       1              : /**
       2              :  *
       3              :  *    Copyright (c) 2025 Project CHIP Authors
       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              : 
      18              : #pragma once
      19              : 
      20              : #include <app/data-model-provider/ProviderMetadataTree.h>
      21              : #include <app/storage/TableEntry.h>
      22              : #include <lib/support/CommonIterator.h>
      23              : #include <lib/support/PersistentData.h>
      24              : #include <lib/support/TypeTraits.h>
      25              : 
      26              : namespace chip {
      27              : namespace app {
      28              : namespace Storage {
      29              : 
      30              : /**
      31              :  * @brief Container which exposes various compile-time constants for specializations
      32              :  * of FabricTableImpl.
      33              :  */
      34              : template <class StorageId, class StorageData>
      35              : class DefaultSerializer
      36              : {
      37              : public:
      38              :     // gcc bug prevents us from using a static variable; see:
      39              :     // https://stackoverflow.com/questions/50638053/constexpr-static-data-member-without-initializer
      40              :     // The number of bytes used by an entry (StorageData) + its metadata when persisting to storage
      41              :     static constexpr size_t kEntryMaxBytes();
      42              :     // The number of bytes used by an ID (StorageId)
      43              :     static constexpr size_t kIdMaxBytes() { return TLV::EstimateStructOverhead(sizeof(StorageId)); }
      44              :     // The number of bytes used by FabricEntryData, which is dependent on the size of StorageId
      45              :     static constexpr size_t kFabricMaxBytes()
      46              :     {
      47              :         return TLV::EstimateStructOverhead(sizeof(uint8_t), // entry_count
      48              :                                            kMaxPerFabric() * kIdMaxBytes());
      49              :     }
      50              :     // The max number of entries per fabric; this value directly affects memory usage
      51              :     static constexpr uint16_t kMaxPerFabric();
      52              :     // The max number of entries for the endpoint (programmatic limit)
      53              :     static constexpr uint16_t kMaxPerEndpoint();
      54              : 
      55              :     DefaultSerializer() {}
      56              :     ~DefaultSerializer(){};
      57              : 
      58              :     static CHIP_ERROR SerializeId(TLV::TLVWriter & writer, const StorageId & id);
      59              :     static CHIP_ERROR DeserializeId(TLV::TLVReader & reader, StorageId & id);
      60              : 
      61              :     static CHIP_ERROR SerializeData(TLV::TLVWriter & writer, const StorageData & data);
      62              :     static CHIP_ERROR DeserializeData(TLV::TLVReader & reader, StorageData & data);
      63              : 
      64              :     static StorageKeyName EndpointEntryCountKey(EndpointId endpoint);
      65              :     // The key for persisting the data for a fabric
      66              :     static StorageKeyName FabricEntryDataKey(FabricIndex fabric, EndpointId endpoint);
      67              :     // The key for persisting the data for an entry in a fabric; FabricEntryDataKey should be a root prefix
      68              :     // of this key, such that removing a fabric removes all its entries
      69              :     static StorageKeyName FabricEntryKey(FabricIndex fabric, EndpointId endpoint, uint16_t idx);
      70              : 
      71              :     // Clears the data to default values
      72          107 :     static void Clear(StorageData & data) { data.Clear(); }
      73              : }; // class DefaultSerializer
      74              : 
      75              : /**
      76              :  * @brief Implementation of a storage accessor in nonvolatile storage of a templatized table that stores by fabric index.
      77              :  *        This class does not actually hold the entries, but rather acts as a wrapper/accessor around the storage layer,
      78              :  *        reading entries from the storage pointed to by calling SetEndpoint.
      79              :  *
      80              :  * FabricTableImpl is an implementation that allows to store arbitrary entities using PersistentStorageDelegate.
      81              :  * It handles the storage of entities by their StorageId and EnpointId over multiple fabrics.
      82              :  */
      83              : template <class StorageId, class StorageData>
      84              : class FabricTableImpl
      85              : {
      86              :     using TableEntry = Data::TableEntryRef<StorageId, StorageData>;
      87              : 
      88              : public:
      89              :     using EntryIterator = CommonIterator<TableEntry>;
      90              :     using EntryIndex    = Data::EntryIndex;
      91              :     using Serializer    = DefaultSerializer<StorageId, StorageData>;
      92              : 
      93           48 :     virtual ~FabricTableImpl() { Finish(); };
      94              : 
      95              :     CHIP_ERROR Init(PersistentStorageDelegate & storage);
      96              :     void Finish();
      97              : 
      98              :     // Entry count
      99              :     /**
     100              :      * @brief Get the total number of stored entries for the entire endpoint
     101              :      * @param entry_count[out] the count of entries
     102              :      * @return CHIP_ERROR, CHIP_NO_ERROR if successful or if the Fabric was not found, specific CHIP_ERROR otherwise
     103              :      */
     104              :     CHIP_ERROR GetEndpointEntryCount(uint8_t & entry_count);
     105              : 
     106              :     /**
     107              :      * @brief Get the total number of stored entries for the specified fabric on the currently selected endpoint.
     108              :      * @param fabric_index the fabric to get the count for
     109              :      * @param entry_count[out] the count of entries
     110              :      * @return CHIP_ERROR, CHIP_NO_ERROR if successful or if the Fabric was not found, specific CHIP_ERROR otherwise
     111              :      */
     112              :     CHIP_ERROR GetFabricEntryCount(FabricIndex fabric_index, uint8_t & entry_count);
     113              : 
     114              :     // Data
     115              :     CHIP_ERROR GetRemainingCapacity(FabricIndex fabric_index, uint8_t & capacity);
     116              : 
     117              :     /**
     118              :      * @brief Writes the entry to persistent storage.
     119              :      * @param fabric_index the fabric to write the entry to
     120              :      * @param entry_id the unique entry identifier
     121              :      * @param data the source data
     122              :      * @param writeBuffer the buffer that will be used to write the data before being persisted; PersistentStorageDelegate does not
     123              :      * offer a way to stream bytes to be written
     124              :      */
     125              :     template <size_t kEntryMaxBytes>
     126              :     CHIP_ERROR SetTableEntry(FabricIndex fabric_index, const StorageId & entry_id, const StorageData & data,
     127              :                              PersistenceBuffer<kEntryMaxBytes> & writeBuffer);
     128              : 
     129              :     /**
     130              :      * @brief Loads the entry from persistent storage.
     131              :      * @param fabric_index the fabric to load the entry from
     132              :      * @param entry_id the unique entry identifier
     133              :      * @param data the target for the loaded data
     134              :      * @param buffer the buffer that will be used to load from persistence; some data types in the data argument, such as
     135              :      * DecodableList, point directly into the buffer, and as such for those types of structures the lifetime of the buffer needs to
     136              :      * be equal to or greater than data
     137              :      */
     138              :     template <size_t kEntryMaxBytes>
     139              :     CHIP_ERROR GetTableEntry(FabricIndex fabric_index, StorageId & entry_id, StorageData & data,
     140              :                              PersistenceBuffer<kEntryMaxBytes> & buffer);
     141              :     CHIP_ERROR FindTableEntry(FabricIndex fabric_index, const StorageId & entry_id, EntryIndex & idx);
     142              :     CHIP_ERROR RemoveTableEntry(FabricIndex fabric_index, const StorageId & entry_id);
     143              :     CHIP_ERROR RemoveTableEntryAtPosition(EndpointId endpoint, FabricIndex fabric_index, EntryIndex entry_idx);
     144              : 
     145              :     // Fabrics
     146              :     CHIP_ERROR RemoveFabric(DataModel::ProviderMetadataTree & provider, FabricIndex fabric_index);
     147              :     CHIP_ERROR RemoveEndpoint();
     148              : 
     149              :     /**
     150              :      * @brief Selects the endpoint that the table will point to & entries will be read from.
     151              :      * @param endpoint the endpoint which entries will be stored to or read from.
     152              :      */
     153              :     void SetEndpoint(EndpointId endpoint);
     154              :     void SetTableSize(uint16_t endpointEntryTableSize, uint16_t maxPerFabric);
     155         1352 :     bool IsInitialized() { return (mStorage != nullptr); }
     156              : 
     157              :     /**
     158              :      * @brief Iterates through all entries in fabric, calling iterateFn with the allocated iterator.
     159              :      * @tparam kEntryMaxBytes size of the buffer for loading entries, should match DefaultSerializer::kEntryMaxBytes
     160              :      * @tparam UnaryFunc a function of type std::function<CHIP_ERROR(EntryIterator & iterator)>; template arg for GCC inlining
     161              :      * efficiency
     162              :      * @param fabric the fabric to iterate entries for
     163              :      * @param store the in-memory buffer that an entry will be read into
     164              :      * @param iterateFn a function that will be called with the iterator; if this function returns an error result, iteration stops
     165              :      * and IterateEntries returns that same error result.
     166              :      */
     167              :     template <size_t kEntryMaxBytes, class UnaryFunc>
     168              :     CHIP_ERROR IterateEntries(FabricIndex fabric, PersistenceBuffer<kEntryMaxBytes> & buffer, UnaryFunc iterateFn);
     169              : 
     170              : protected:
     171              :     // This constructor is meant for test purposes, it allows to change the defined max for entries per fabric and global, which
     172              :     // allows to simulate OTA where this value was changed
     173           48 :     FabricTableImpl(uint16_t maxEntriesPerFabric, uint16_t maxEntriesPerEndpoint) :
     174           48 :         mMaxPerFabric(maxEntriesPerFabric), mMaxPerEndpoint(maxEntriesPerEndpoint)
     175           48 :     {}
     176              : 
     177              :     // Endpoint entry count
     178              :     CHIP_ERROR SetEndpointEntryCount(const uint8_t & entry_count);
     179              : 
     180              :     /**
     181              :      * @brief Implementation of an iterator over the elements in the FabricTableImpl.
     182              :      *
     183              :      * If you would like to expose iterators in your subclass of FabricTableImpl, you can:
     184              :      * A) Use this class in an ObjectPool<EntryIteratorImpl> field to allow callers to obtain an iterator, with AutoRelease to free
     185              :      * resources B) Use IterateEntries to allocate on stack
     186              :      */
     187              :     template <size_t kEntryMaxBytes>
     188              :     class EntryIteratorImpl : public EntryIterator
     189              :     {
     190              :     public:
     191              :         EntryIteratorImpl(FabricTableImpl & provider, FabricIndex fabricIdx, EndpointId endpoint, uint16_t maxEntriesPerFabric,
     192              :                           uint16_t maxEntriesPerEndpoint, PersistenceBuffer<kEntryMaxBytes> & buffer);
     193              :         size_t Count() override;
     194              :         bool Next(TableEntry & output) override;
     195              :         void Release() override;
     196              : 
     197              :     protected:
     198              :         FabricTableImpl & mProvider;
     199              :         PersistenceBuffer<kEntryMaxBytes> & mBuffer;
     200              :         FabricIndex mFabric  = kUndefinedFabricIndex;
     201              :         EndpointId mEndpoint = kInvalidEndpointId;
     202              :         EntryIndex mNextEntryIdx;
     203              :         EntryIndex mEntryIndex = 0;
     204              :         uint8_t mTotalEntries  = 0;
     205              :         uint16_t mMaxPerFabric;
     206              :         uint16_t mMaxPerEndpoint;
     207              :     };
     208              : 
     209              :     uint16_t mMaxPerFabric;
     210              :     uint16_t mMaxPerEndpoint;
     211              :     EndpointId mEndpointId               = kInvalidEndpointId;
     212              :     PersistentStorageDelegate * mStorage = nullptr;
     213              : }; // class FabricTableImpl
     214              : 
     215              : } // namespace Storage
     216              : } // namespace app
     217              : } // namespace chip
        

Generated by: LCOV version 2.0-1