Matter SDK Coverage Report
Current view: top level - app/data-model - Encode.h (source / functions) Coverage Total Hit
Test: SHA:3640a4f95bebd68003e5aea27c711ffe4cd39423 Lines: 81.8 % 33 27
Test Date: 2025-09-13 07:10:37 Functions: 46.8 % 154 72

            Line data    Source code
       1              : /*
       2              :  *
       3              :  *    Copyright (c) 2020-2021 Project CHIP Authors
       4              :  *    All rights reserved.
       5              :  *
       6              :  *    Licensed under the Apache License, Version 2.0 (the "License");
       7              :  *    you may not use this file except in compliance with the License.
       8              :  *    You may obtain a copy of the License at
       9              :  *
      10              :  *        http://www.apache.org/licenses/LICENSE-2.0
      11              :  *
      12              :  *    Unless required by applicable law or agreed to in writing, software
      13              :  *    distributed under the License is distributed on an "AS IS" BASIS,
      14              :  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      15              :  *    See the License for the specific language governing permissions and
      16              :  *    limitations under the License.
      17              :  */
      18              : 
      19              : #pragma once
      20              : 
      21              : #include <app/data-model/FabricScoped.h>
      22              : #include <app/data-model/Nullable.h>
      23              : #include <lib/core/CHIPConfig.h>
      24              : #include <lib/core/DataModelTypes.h>
      25              : #include <lib/core/Optional.h>
      26              : #include <lib/core/TLV.h>
      27              : #include <protocols/interaction_model/Constants.h>
      28              : 
      29              : #include <type_traits>
      30              : 
      31              : namespace chip {
      32              : namespace app {
      33              : namespace DataModel {
      34              : 
      35              : namespace detail {
      36              : // A way to detect whether an enum has a kUnknownEnumValue value, for use in enable_if.
      37              : template <typename Enum, Enum value>
      38              : using VoidType = void;
      39              : 
      40              : template <typename, typename = void>
      41              : inline constexpr bool HasUnknownValue = false;
      42              : 
      43              : template <typename T>
      44              : inline constexpr bool HasUnknownValue<T, VoidType<T, T::kUnknownEnumValue>> = true;
      45              : } // namespace detail
      46              : 
      47              : /*
      48              :  * @brief
      49              :  * Set of overloaded encode methods that based on the type of cluster element passed in,
      50              :  * appropriately encodes them to TLV.
      51              :  */
      52              : template <typename X, typename std::enable_if_t<std::is_integral<X>::value, int> = 0>
      53        14462 : CHIP_ERROR Encode(TLV::TLVWriter & writer, TLV::Tag tag, X x)
      54              : {
      55        14462 :     return writer.Put(tag, x);
      56              : }
      57              : 
      58              : template <typename X, typename std::enable_if_t<std::is_floating_point<X>::value, int> = 0>
      59          100 : CHIP_ERROR Encode(TLV::TLVWriter & writer, TLV::Tag tag, X x)
      60              : {
      61          100 :     return writer.Put(tag, x);
      62              : }
      63              : 
      64              : template <typename X, typename std::enable_if_t<std::is_enum<X>::value && !detail::HasUnknownValue<X>, int> = 0>
      65            0 : CHIP_ERROR Encode(TLV::TLVWriter & writer, TLV::Tag tag, X x)
      66              : {
      67            0 :     return writer.Put(tag, x);
      68              : }
      69              : 
      70              : // Reusable macro for dealing with unknown enum values that we can use in
      71              : // attribute value encoding.
      72              : #if CHIP_CONFIG_IM_ENABLE_ENCODING_SENTINEL_ENUM_VALUES
      73              : #define CHIP_DM_ENCODING_MAYBE_FAIL_UNKNOWN_ENUM_VALUE(value)                                                                      \
      74              :     do                                                                                                                             \
      75              :     {                                                                                                                              \
      76              :         /* Nothing to do */                                                                                                        \
      77              :     } while (0)
      78              : #else
      79              : #define CHIP_DM_ENCODING_MAYBE_FAIL_UNKNOWN_ENUM_VALUE(value)                                                                      \
      80              :     do                                                                                                                             \
      81              :     {                                                                                                                              \
      82              :         if (value == std::remove_reference_t<decltype(value)>::kUnknownEnumValue)                                                  \
      83              :         {                                                                                                                          \
      84              :             return CHIP_IM_GLOBAL_STATUS(ConstraintError);                                                                         \
      85              :         }                                                                                                                          \
      86              :     } while (0)
      87              : #endif // CHIP_CONFIG_IM_ENABLE_ENCODING_SENTINEL_ENUM_VALUES
      88              : 
      89              : template <typename X, typename std::enable_if_t<std::is_enum<X>::value && detail::HasUnknownValue<X>, int> = 0>
      90           51 : CHIP_ERROR Encode(TLV::TLVWriter & writer, TLV::Tag tag, X x)
      91              : {
      92           51 :     CHIP_DM_ENCODING_MAYBE_FAIL_UNKNOWN_ENUM_VALUE(x);
      93              : 
      94           51 :     return writer.Put(tag, x);
      95              : }
      96              : 
      97              : template <typename X>
      98              : CHIP_ERROR Encode(TLV::TLVWriter & writer, TLV::Tag tag, BitFlags<X> x)
      99              : {
     100              :     return writer.Put(tag, x);
     101              : }
     102              : 
     103        14281 : inline CHIP_ERROR Encode(TLV::TLVWriter & writer, TLV::Tag tag, ByteSpan x)
     104              : {
     105        14281 :     return writer.Put(tag, x);
     106              : }
     107              : 
     108          119 : inline CHIP_ERROR Encode(TLV::TLVWriter & writer, TLV::Tag tag, Span<const char> x)
     109              : {
     110          119 :     return writer.PutString(tag, x);
     111              : }
     112              : 
     113              : /*
     114              :  * @brief
     115              :  *
     116              :  * This specific variant that encodes cluster objects (like non fabric-scoped structs, commands, events) to TLV
     117              :  * depends on the presence of an Encode method on the object. The signature of that method
     118              :  * is as follows:
     119              :  *
     120              :  * CHIP_ERROR <Object>::Encode(TLVWriter &writer, TLV::Tag tag) const;
     121              :  *
     122              :  *
     123              :  */
     124              : template <typename X,
     125              :           typename std::enable_if_t<
     126              :               std::is_class<X>::value &&
     127              :                   std::is_same<decltype(std::declval<X>().Encode(std::declval<TLV::TLVWriter &>(), std::declval<TLV::Tag>())),
     128              :                                CHIP_ERROR>::value,
     129              :               X> * = nullptr>
     130         6490 : CHIP_ERROR Encode(TLV::TLVWriter & writer, TLV::Tag tag, const X & x)
     131              : {
     132         6490 :     return x.Encode(writer, tag);
     133              : }
     134              : 
     135              : /*
     136              :  * @brief
     137              :  *
     138              :  * A way to encode fabric-scoped structs for a write that omits encoding the containing fabric index field.
     139              :  */
     140              : template <typename X,
     141              :           typename std::enable_if_t<std::is_class<X>::value &&
     142              :                                         std::is_same<decltype(std::declval<X>().EncodeForWrite(std::declval<TLV::TLVWriter &>(),
     143              :                                                                                                std::declval<TLV::Tag>())),
     144              :                                                      CHIP_ERROR>::value &&
     145              :                                         DataModel::IsFabricScoped<X>::value,
     146              :                                     X> * = nullptr>
     147            8 : CHIP_ERROR EncodeForWrite(TLV::TLVWriter & writer, TLV::Tag tag, const X & x)
     148              : {
     149            8 :     return x.EncodeForWrite(writer, tag);
     150              : }
     151              : 
     152              : /*
     153              :  * @brief
     154              :  *
     155              :  * A way to encode fabric-scoped structs for a read that always encodes the containing fabric index field.
     156              :  *
     157              :  * An accessing fabric index must be passed in to permit including/omitting sensitive fields based on a match with the fabric index
     158              :  * associated with the scoped struct.
     159              :  */
     160              : template <typename X,
     161              :           typename std::enable_if_t<
     162              :               std::is_class<X>::value &&
     163              :                   std::is_same<decltype(std::declval<X>().EncodeForRead(std::declval<TLV::TLVWriter &>(), std::declval<TLV::Tag>(),
     164              :                                                                         std::declval<FabricIndex>())),
     165              :                                CHIP_ERROR>::value &&
     166              :                   DataModel::IsFabricScoped<X>::value,
     167              :               X> * = nullptr>
     168           81 : CHIP_ERROR EncodeForRead(TLV::TLVWriter & writer, TLV::Tag tag, FabricIndex accessingFabricIndex, const X & x)
     169              : {
     170           81 :     return x.EncodeForRead(writer, tag, accessingFabricIndex);
     171              : }
     172              : 
     173              : /*
     174              :  * @brief
     175              :  *
     176              :  * Encodes an optional value (struct field, command field, event field).
     177              :  */
     178              : template <typename X>
     179            0 : CHIP_ERROR Encode(TLV::TLVWriter & writer, TLV::Tag tag, const Optional<X> & x)
     180              : {
     181            0 :     if (x.HasValue())
     182              :     {
     183            0 :         return Encode(writer, tag, x.Value());
     184              :     }
     185              :     // If no value, just do nothing.
     186            0 :     return CHIP_NO_ERROR;
     187              : }
     188              : 
     189              : /*
     190              :  * @brief
     191              :  *
     192              :  * Encodes a nullable value.
     193              :  */
     194              : template <typename X>
     195        11270 : CHIP_ERROR Encode(TLV::TLVWriter & writer, TLV::Tag tag, const Nullable<X> & x)
     196              : {
     197        11270 :     if (x.IsNull())
     198              :     {
     199        11225 :         return writer.PutNull(tag);
     200              :     }
     201              : 
     202              :     // Allow sending invalid values for nullables when
     203              :     // CONFIG_BUILD_FOR_HOST_UNIT_TEST is true, so we can test how the other side
     204              :     // responds.
     205              : #if !CONFIG_BUILD_FOR_HOST_UNIT_TEST
     206              :     if (!x.ExistingValueInEncodableRange())
     207              :     {
     208              :         return CHIP_IM_GLOBAL_STATUS(ConstraintError);
     209              :     }
     210              : #endif // !CONFIG_BUILD_FOR_HOST_UNIT_TEST
     211              : 
     212              :     // The -Wmaybe-uninitialized warning gets confused about the fact
     213              :     // that x.mValue is always initialized if x.IsNull() is not
     214              :     // true, so suppress it for our access to x.Value().
     215              : #pragma GCC diagnostic push
     216              : #if !defined(__clang__)
     217              : #pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
     218              : #endif // !defined(__clang__)
     219           45 :     return Encode(writer, tag, x.Value());
     220              : #pragma GCC diagnostic pop
     221              : }
     222              : 
     223              : /*
     224              :  * @brief
     225              :  *
     226              :  * Encodes a nullable fabric-scoped struct for a write.
     227              :  */
     228              : template <typename X, std::enable_if_t<DataModel::IsFabricScoped<X>::value, bool> = true>
     229              : CHIP_ERROR EncodeForWrite(TLV::TLVWriter & writer, TLV::Tag tag, const Nullable<X> & x)
     230              : {
     231              :     if (x.IsNull())
     232              :     {
     233              :         return writer.PutNull(tag);
     234              :     }
     235              : 
     236              :     // The -Wmaybe-uninitialized warning gets confused about the fact
     237              :     // that x.mValue is always initialized if x.IsNull() is not
     238              :     // true, so suppress it for our access to x.Value().
     239              : #pragma GCC diagnostic push
     240              : #if !defined(__clang__)
     241              : #pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
     242              : #endif // !defined(__clang__)
     243              :     return EncodeForWrite(writer, tag, x.Value());
     244              : #pragma GCC diagnostic pop
     245              : }
     246              : 
     247              : /*
     248              :  * @brief
     249              :  *
     250              :  * Encodes a nullable fabric-scoped struct for a read.
     251              :  */
     252              : template <typename X, std::enable_if_t<DataModel::IsFabricScoped<X>::value, bool> = true>
     253              : CHIP_ERROR EncodeForRead(TLV::TLVWriter & writer, TLV::Tag tag, FabricIndex accessingFabricIndex, const Nullable<X> & x)
     254              : {
     255              :     if (x.IsNull())
     256              :     {
     257              :         return writer.PutNull(tag);
     258              :     }
     259              : 
     260              :     // The -Wmaybe-uninitialized warning gets confused about the fact
     261              :     // that x.mValue is always initialized if x.IsNull() is not
     262              :     // true, so suppress it for our access to x.Value().
     263              : #pragma GCC diagnostic push
     264              : #if !defined(__clang__)
     265              : #pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
     266              : #endif // !defined(__clang__)
     267              :     return EncodeForRead(writer, tag, accessingFabricIndex, x.Value());
     268              : #pragma GCC diagnostic pop
     269              : }
     270              : 
     271              : // Should this be declared in a separate header?
     272              : struct FabricAwareTLVWriter
     273              : {
     274           24 :     FabricAwareTLVWriter(TLV::TLVWriter & writer, FabricIndex accessingFabricIndex) :
     275           24 :         mTLVWriter(writer), mAccessingFabricIndex(accessingFabricIndex)
     276           24 :     {}
     277              : 
     278           19 :     operator TLV::TLVWriter &() { return mTLVWriter; }
     279              : 
     280              :     TLV::TLVWriter & mTLVWriter;
     281              :     const FabricIndex mAccessingFabricIndex;
     282              : };
     283              : 
     284              : /**
     285              :  * @brief
     286              :  *
     287              :  * Encodes a response command payload. This is a templated function to allow
     288              :  * specializations to be created as needed to customize the behavior.
     289              :  */
     290              : template <typename PayloadType>
     291           11 : CHIP_ERROR EncodeResponseCommandPayload(FabricAwareTLVWriter & writer, TLV::Tag tag, const PayloadType & payload)
     292              : {
     293           11 :     return payload.Encode(writer, tag);
     294              : }
     295              : 
     296              : } // namespace DataModel
     297              : } // namespace app
     298              : } // namespace chip
        

Generated by: LCOV version 2.0-1