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-common/zap-generated/cluster-enums-check.h>
22 : #include <app/ConcreteAttributePath.h>
23 : #include <app/data-model/Nullable.h>
24 : #include <lib/core/CHIPError.h>
25 : #include <lib/core/CHIPSafeCasts.h>
26 : #include <lib/core/Optional.h>
27 : #include <lib/core/TLV.h>
28 : #include <protocols/interaction_model/Constants.h>
29 :
30 : namespace chip {
31 : namespace app {
32 : namespace Clusters {
33 0 : static auto __attribute__((unused)) EnsureKnownEnumValue(chip::VendorId val)
34 : {
35 0 : return val;
36 : }
37 : } // namespace Clusters
38 :
39 : namespace DataModel {
40 :
41 : //
42 : // Decode
43 : //
44 : template <typename X, typename std::enable_if_t<std::is_integral<X>::value, int> = 0>
45 0 : CHIP_ERROR Decode(TLV::TLVReader & reader, X & x)
46 : {
47 0 : return reader.Get(x);
48 : }
49 :
50 : template <typename X, typename std::enable_if_t<std::is_floating_point<X>::value, int> = 0>
51 : CHIP_ERROR Decode(TLV::TLVReader & reader, X & x)
52 : {
53 : return reader.Get(x);
54 : }
55 :
56 : template <typename X, typename std::enable_if_t<std::is_enum<X>::value, int> = 0>
57 3 : CHIP_ERROR Decode(TLV::TLVReader & reader, X & x)
58 : {
59 3 : ReturnErrorOnFailure(reader.Get(x));
60 3 : x = Clusters::EnsureKnownEnumValue(x);
61 3 : return CHIP_NO_ERROR;
62 : }
63 :
64 : template <typename X>
65 0 : CHIP_ERROR Decode(TLV::TLVReader & reader, BitFlags<X> & x)
66 : {
67 0 : return reader.Get(x);
68 : }
69 :
70 : //
71 : // @brief
72 : //
73 : // Decodes an octet string that is expected at the positioned reader.
74 : //
75 : // The passed in ByteSpan is ignored and updated to point directly into
76 : // the buffer backing the reader.
77 : //
78 : inline CHIP_ERROR Decode(TLV::TLVReader & reader, ByteSpan & x)
79 : {
80 : VerifyOrReturnError(reader.GetType() == TLV::kTLVType_ByteString, CHIP_ERROR_UNEXPECTED_TLV_ELEMENT);
81 : return reader.Get(x);
82 : }
83 :
84 : //
85 : // @brief
86 : //
87 : // Decodes a UTF-8 string that is expected at the positioned reader.
88 : //
89 : // The passed in char Span is ignored and updated to point directly into
90 : // the buffer backing the reader.
91 : //
92 0 : inline CHIP_ERROR Decode(TLV::TLVReader & reader, Span<const char> & x)
93 : {
94 0 : return reader.Get(x);
95 : }
96 :
97 : /*
98 : * @brief
99 : *
100 : * This specific variant that decodes cluster objects (like structs, commands, events) from TLV
101 : * depends on the presence of a Decode method on the object to present. The signature of that method
102 : * is as follows:
103 : *
104 : * CHIP_ERROR <Object>::Decode(TLVReader &reader);
105 : *
106 : */
107 : template <typename X,
108 : typename std::enable_if_t<
109 : std::is_class<X>::value &&
110 : std::is_same<decltype(std::declval<X>().Decode(std::declval<TLV::TLVReader &>())), CHIP_ERROR>::value,
111 : X> * = nullptr>
112 0 : CHIP_ERROR Decode(TLV::TLVReader & reader, X & x)
113 : {
114 0 : return x.Decode(reader);
115 : }
116 :
117 : /*
118 : * @brief
119 : *
120 : * This specific variant decodes from TLV a cluster object that contains all attributes encapsulated within a single, monolithic
121 : * cluster object.
122 : *
123 : * Each attribute in the cluster is decoded based on the provided ConcreteAttributePath. The TLVReader is to be positioned right on
124 : * the data value for the specified attribute.
125 : *
126 : * This API depends on the presence of a Decode method on the object. The signature of that method
127 : * is as follows:
128 : *
129 : * CHIP_ERROR <Object>::Decode(TLVReader &reader, ConcreteAttributePath &path);
130 : *
131 : */
132 : template <
133 : typename X,
134 : typename std::enable_if_t<std::is_class<X>::value &&
135 : std::is_same<decltype(std::declval<X>().Decode(std::declval<TLV::TLVReader &>(),
136 : std::declval<const ConcreteAttributePath &>())),
137 : CHIP_ERROR>::value,
138 : X> * = nullptr>
139 : CHIP_ERROR Decode(TLV::TLVReader & reader, const ConcreteAttributePath & path, X & x)
140 : {
141 : return x.Decode(reader, path);
142 : }
143 :
144 : /*
145 : * @brief
146 : *
147 : * Decodes an optional value (struct field, command field, event field).
148 : */
149 : template <typename X>
150 : CHIP_ERROR Decode(TLV::TLVReader & reader, Optional<X> & x)
151 : {
152 : // If we are calling this, it means we found the right tag, so just decode
153 : // the item.
154 : return Decode(reader, x.Emplace());
155 : }
156 :
157 : /*
158 : * @brief
159 : *
160 : * Decodes a nullable value.
161 : */
162 : template <typename X>
163 0 : CHIP_ERROR Decode(TLV::TLVReader & reader, Nullable<X> & x)
164 : {
165 0 : if (reader.GetType() == TLV::kTLVType_Null)
166 : {
167 0 : x.SetNull();
168 0 : return CHIP_NO_ERROR;
169 : }
170 :
171 : // We have a value; decode it.
172 0 : ReturnErrorOnFailure(Decode(reader, x.SetNonNull()));
173 0 : if (!x.ExistingValueInEncodableRange())
174 : {
175 0 : return CHIP_IM_GLOBAL_STATUS(ConstraintError);
176 : }
177 0 : return CHIP_NO_ERROR;
178 : }
179 :
180 : } // namespace DataModel
181 : } // namespace app
182 : } // namespace chip
|