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/data-model-provider/MetadataTypes.h>
20 : #include <app/server-cluster/ServerClusterInterface.h>
21 : #include <data-model-providers/codedriven/endpoint/EndpointInterface.h>
22 : #include <lib/core/DataModelTypes.h>
23 : #include <lib/support/Span.h>
24 :
25 : #include <variant>
26 :
27 : namespace chip {
28 : namespace app {
29 :
30 : /**
31 : * @brief An implementation of EndpointInterface that uses `chip::Span` to refer to its data.
32 : *
33 : * This provider is constructed using its `Builder` class. It stores `chip::Span` members that
34 : * point to externally managed arrays for its configuration (device types, server/client clusters,
35 : * semantic tags, etc.).
36 : *
37 : * @warning Lifetime of Span-Referenced Data:
38 : * `SpanEndpoint` does NOT take ownership of the data arrays referenced by its
39 : * internal `chip::Span` members. The caller who provides these Spans (usually via the
40 : * `Builder`) MUST ensure that the underlying data remains valid for the entire lifetime
41 : * of the `SpanEndpoint` instance.
42 : * - For `Span<T>` (e.g., `Span<const ClusterId>`, `Span<const DeviceTypeEntry>`), the
43 : * array of `T` elements must outlive the `SpanEndpoint`.
44 : * - For `Span<T*>` (e.g., `Span<ServerClusterInterface *>`), both the array of pointers
45 : * (`T*`) and the objects (`T`) pointed to by those pointers must outlive the
46 : * `SpanEndpoint`.
47 : * Failure to adhere to these lifetime requirements will lead to undefined behavior.
48 : */
49 : class SpanEndpoint : public EndpointInterface
50 : {
51 : public:
52 : class Builder
53 : {
54 : public:
55 : explicit Builder(EndpointId id);
56 :
57 : Builder & SetComposition(DataModel::EndpointCompositionPattern composition);
58 : Builder & SetParentId(EndpointId parentId);
59 : Builder & SetServerClusters(Span<ServerClusterInterface *> serverClusters);
60 : Builder & SetClientClusters(Span<const ClusterId> clientClusters);
61 : Builder & SetSemanticTags(Span<const SemanticTag> semanticTags);
62 : Builder & SetDeviceTypes(Span<const DataModel::DeviceTypeEntry> deviceTypes);
63 :
64 : // Builds the SpanEndpoint.
65 : // Returns a std::variant containing either the successfully built SpanEndpoint
66 : // or a CHIP_ERROR if the build failed (e.g., due to invalid arguments).
67 : // Callers should check the variant's active alternative before use.
68 : std::variant<SpanEndpoint, CHIP_ERROR> Build();
69 :
70 : private:
71 : EndpointId mEndpointId;
72 : DataModel::EndpointCompositionPattern mComposition = DataModel::EndpointCompositionPattern::kFullFamily;
73 : EndpointId mParentId = kInvalidEndpointId;
74 : Span<ServerClusterInterface *> mServerClusters;
75 : Span<const ClusterId> mClientClusters;
76 : Span<const SemanticTag> mSemanticTags;
77 : Span<const DataModel::DeviceTypeEntry> mDeviceTypes;
78 : };
79 :
80 470 : ~SpanEndpoint() override = default;
81 :
82 : // Delete copy constructor and assignment operator. SpanEndpoint holds non-owning data (Spans).
83 : // This helps prevent accidental copies that could lead multiple objects pointing to the same external data.
84 : SpanEndpoint(const SpanEndpoint &) = delete;
85 : SpanEndpoint & operator=(const SpanEndpoint &) = delete;
86 :
87 : // Allow move semantics for SpanEndpoint.
88 235 : SpanEndpoint(SpanEndpoint &&) = default;
89 : SpanEndpoint & operator=(SpanEndpoint &&) = default;
90 :
91 33180 : const DataModel::EndpointEntry & GetEndpointEntry() const override { return mEndpointEntry; }
92 :
93 : // Iteration methods
94 : CHIP_ERROR SemanticTags(ReadOnlyBufferBuilder<SemanticTag> & out) const override;
95 : CHIP_ERROR DeviceTypes(ReadOnlyBufferBuilder<DataModel::DeviceTypeEntry> & out) const override;
96 : CHIP_ERROR ClientClusters(ReadOnlyBufferBuilder<ClusterId> & out) const override;
97 :
98 : // Getter for ServerClusterInterface, returns nullptr if the cluster is not found.
99 : ServerClusterInterface * GetServerCluster(ClusterId clusterId) const override;
100 : CHIP_ERROR ServerClusters(ReadOnlyBufferBuilder<ServerClusterInterface *> & out) const override;
101 :
102 : private:
103 : // Private constructor for Builder
104 : SpanEndpoint(EndpointId id, DataModel::EndpointCompositionPattern composition, EndpointId parentId,
105 : Span<ServerClusterInterface *> serverClusters, Span<const ClusterId> clientClusters,
106 : Span<const SemanticTag> semanticTags, Span<const DataModel::DeviceTypeEntry> deviceTypes);
107 :
108 : // Iteration methods
109 : // GetEndpointEntry is already public
110 : DataModel::EndpointEntry mEndpointEntry;
111 : Span<const DataModel::DeviceTypeEntry> mDeviceTypes;
112 : Span<const SemanticTag> mSemanticTags;
113 : Span<const ClusterId> mClientClusters;
114 : Span<ServerClusterInterface *> mServerClusters;
115 : };
116 :
117 : } // namespace app
118 : } // namespace chip
|