Line data Source code
1 : /**
2 : * Copyright (c) 2024 Project CHIP Authors
3 : *
4 : * Licensed under the Apache License, Version 2.0 (the "License");
5 : * you may not use this file except in compliance with the License.
6 : * You may obtain a copy of the License at
7 : *
8 : * http://www.apache.org/licenses/LICENSE-2.0
9 : *
10 : * Unless required by applicable law or agreed to in writing, software
11 : * distributed under the License is distributed on an "AS IS" BASIS,
12 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 : * See the License for the specific language governing permissions and
14 : * limitations under the License.
15 : */
16 : #include "app/AttributeAccessInterface.h"
17 : #include <app/AttributeAccessInterfaceRegistry.h>
18 :
19 : #include <app/AttributeAccessInterfaceCache.h>
20 :
21 : namespace {
22 :
23 : using chip::app::AttributeAccessInterface;
24 :
25 : // shouldUnregister returns true if the given AttributeAccessInterface should be
26 : // unregistered.
27 : template <typename F>
28 31 : void UnregisterMatchingAttributeAccessInterfaces(F shouldUnregister, AttributeAccessInterface *& list_head)
29 : {
30 31 : AttributeAccessInterface * prev = nullptr;
31 31 : AttributeAccessInterface * cur = list_head;
32 54 : while (cur)
33 : {
34 23 : AttributeAccessInterface * next = cur->GetNext();
35 23 : if (shouldUnregister(cur))
36 : {
37 : // Remove it from the list
38 8 : if (prev)
39 : {
40 0 : prev->SetNext(next);
41 : }
42 : else
43 : {
44 8 : list_head = next;
45 : }
46 :
47 8 : cur->SetNext(nullptr);
48 :
49 : // Do not change prev in this case.
50 : }
51 : else
52 : {
53 15 : prev = cur;
54 : }
55 23 : cur = next;
56 : }
57 31 : }
58 :
59 : } // namespace
60 :
61 : namespace chip {
62 : namespace app {
63 :
64 5244 : AttributeAccessInterfaceRegistry & AttributeAccessInterfaceRegistry::Instance()
65 : {
66 5244 : static AttributeAccessInterfaceRegistry instance;
67 5244 : return instance;
68 : }
69 :
70 8 : void AttributeAccessInterfaceRegistry::Unregister(AttributeAccessInterface * attrOverride)
71 : {
72 8 : mAttributeAccessInterfaceCache.Invalidate();
73 8 : UnregisterMatchingAttributeAccessInterfaces([attrOverride](AttributeAccessInterface * entry) { return entry == attrOverride; },
74 8 : mAttributeAccessOverrides);
75 8 : }
76 :
77 23 : void AttributeAccessInterfaceRegistry::UnregisterAllForEndpoint(EndpointId endpointId)
78 : {
79 23 : mAttributeAccessInterfaceCache.Invalidate();
80 23 : UnregisterMatchingAttributeAccessInterfaces(
81 38 : [endpointId](AttributeAccessInterface * entry) { return entry->MatchesEndpoint(endpointId); }, mAttributeAccessOverrides);
82 23 : }
83 :
84 15 : bool AttributeAccessInterfaceRegistry::Register(AttributeAccessInterface * attrOverride)
85 : {
86 15 : mAttributeAccessInterfaceCache.Invalidate();
87 15 : for (auto * cur = mAttributeAccessOverrides; cur; cur = cur->GetNext())
88 : {
89 4 : if (cur->Matches(*attrOverride))
90 : {
91 4 : ChipLogError(InteractionModel, "Duplicate attribute override registration failed");
92 4 : return false;
93 : }
94 : }
95 11 : attrOverride->SetNext(mAttributeAccessOverrides);
96 11 : mAttributeAccessOverrides = attrOverride;
97 11 : return true;
98 : }
99 :
100 5198 : AttributeAccessInterface * AttributeAccessInterfaceRegistry::Get(EndpointId endpointId, ClusterId clusterId)
101 : {
102 : using CacheResult = AttributeAccessInterfaceCache::CacheResult;
103 :
104 5198 : AttributeAccessInterface * cached = nullptr;
105 5198 : CacheResult result = mAttributeAccessInterfaceCache.Get(endpointId, clusterId, &cached);
106 5198 : switch (result)
107 : {
108 179 : case CacheResult::kDefinitelyUnused:
109 179 : return nullptr;
110 4989 : case CacheResult::kDefinitelyUsed:
111 4989 : return cached;
112 30 : case CacheResult::kCacheMiss:
113 : default:
114 : // Did not cache yet, search set of AAI registered, and cache if found.
115 30 : for (app::AttributeAccessInterface * cur = mAttributeAccessOverrides; cur; cur = cur->GetNext())
116 : {
117 25 : if (cur->Matches(endpointId, clusterId))
118 : {
119 25 : mAttributeAccessInterfaceCache.MarkUsed(endpointId, clusterId, cur);
120 25 : return cur;
121 : }
122 : }
123 :
124 : // Did not find AAI registered: mark as definitely not using.
125 5 : mAttributeAccessInterfaceCache.MarkUnused(endpointId, clusterId);
126 : }
127 :
128 5 : return nullptr;
129 : }
130 :
131 : } // namespace app
132 : } // namespace chip
|