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/Decode.h>
22 : #include <app/data-model/Encode.h>
23 : #include <app/data-model/FabricScoped.h>
24 : #include <lib/core/TLV.h>
25 :
26 : namespace chip {
27 : namespace app {
28 : namespace DataModel {
29 :
30 : /*
31 : * Dedicated type for list<T> that is at its base, just a Span.
32 : *
33 : * Motivated by the need to create distinction between Lists that use Spans
34 : * vs. other data model types that use Spans (like octetstr). These have different
35 : * encodings. Consequently, there needs to be an actual C++ type distinction to ensure
36 : * correct specialization of the Encode/Decode methods.
37 : *
38 : */
39 : template <typename T>
40 : struct List : public Span<T>
41 : {
42 : //
43 : // The following 'using' statements are needed to make visible
44 : // all constructors of the base class within this derived class,
45 : // as well as introduce functions in the base class into the
46 : // derived class.
47 : //
48 : // This is needed to make it seamless to initialize and interact with
49 : // List<T> instances as though they were just Spans.
50 : //
51 : using Span<T>::Span;
52 :
53 : // Inherited copy constructors are _not_ imported by the using statement
54 : // above, though, so we need to implement that ourselves. This is templated
55 : // on the span's type to allow us to init a List<const Foo> from Span<Foo>.
56 : // Span's constructor handles the checks on the types for us.
57 : template <class U>
58 31 : constexpr List(const Span<U> & other) : Span<T>(other)
59 31 : {}
60 :
61 : template <size_t N>
62 847 : constexpr List & operator=(T (&databuf)[N])
63 : {
64 847 : Span<T>::operator=(databuf);
65 847 : return (*this);
66 : }
67 :
68 : //
69 : // A list is deemed fabric scoped if the type of its elements is as well.
70 : //
71 : static constexpr bool kIsFabricScoped = DataModel::IsFabricScoped<T>::value;
72 : };
73 :
74 : // Template deduction guides to allow construction of List from a pointer or
75 : // array without having to specify the type of the list entries explicitly.
76 : template <class T>
77 : List(T * data, size_t size) -> List<T>;
78 : template <class T, size_t N>
79 : List(T (&databuf)[N]) -> List<T>;
80 :
81 : template <typename X>
82 1460 : inline CHIP_ERROR Encode(TLV::TLVWriter & writer, TLV::Tag tag, List<X> list)
83 : {
84 : TLV::TLVType type;
85 :
86 1460 : ReturnErrorOnFailure(writer.StartContainer(tag, TLV::kTLVType_Array, type));
87 6166 : for (auto & item : list)
88 : {
89 4707 : ReturnErrorOnFailure(Encode(writer, TLV::AnonymousTag(), item));
90 : }
91 1459 : ReturnErrorOnFailure(writer.EndContainer(type));
92 :
93 1459 : return CHIP_NO_ERROR;
94 : }
95 :
96 : template <typename X, std::enable_if_t<DataModel::IsFabricScoped<X>::value, bool> = true>
97 1 : inline CHIP_ERROR EncodeForWrite(TLV::TLVWriter & writer, TLV::Tag tag, List<X> list)
98 : {
99 : TLV::TLVType type;
100 :
101 1 : ReturnErrorOnFailure(writer.StartContainer(tag, TLV::kTLVType_Array, type));
102 4 : for (auto & item : list)
103 : {
104 3 : ReturnErrorOnFailure(EncodeForWrite(writer, TLV::AnonymousTag(), item));
105 : }
106 1 : ReturnErrorOnFailure(writer.EndContainer(type));
107 :
108 1 : return CHIP_NO_ERROR;
109 : }
110 :
111 : template <typename X, std::enable_if_t<DataModel::IsFabricScoped<X>::value, bool> = true>
112 : inline CHIP_ERROR EncodeForRead(TLV::TLVWriter & writer, TLV::Tag tag, FabricIndex accessingFabricIndex, List<X> list)
113 : {
114 : TLV::TLVType type;
115 :
116 : ReturnErrorOnFailure(writer.StartContainer(tag, TLV::kTLVType_Array, type));
117 : for (auto & item : list)
118 : {
119 : ReturnErrorOnFailure(EncodeForRead(writer, TLV::AnonymousTag(), accessingFabricIndex, item));
120 : }
121 : ReturnErrorOnFailure(writer.EndContainer(type));
122 :
123 : return CHIP_NO_ERROR;
124 : }
125 :
126 : } // namespace DataModel
127 : } // namespace app
128 : } // namespace chip
|