blob: 143517c6b64c5ed3af04a888f41ec9ae7eef93ca [file] [log] [blame]
/*
* Copyright (c) 2025 Project CHIP Authors
* All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include <app/server-cluster/ServerClusterInterfaceRegistry.h>
namespace chip {
namespace app {
/// This class specializes ServerClusterInterfaceRegistry to register ServerClusterInterface references
/// that are limited to a single endpoint. In other words, GetPaths() must return path(s) in the same
/// endpoint.
/// The assumption that every ServerClusterInterface registered is limited to a single endpoint
/// allows us to provide additional helper methods such as `ClustersOnEndpoint()` and `UnregisterAllFromEndpoint()`.
class SingleEndpointServerClusterRegistry : public ServerClusterInterfaceRegistry
{
public:
/// represents an iterable list of clusters
class ClustersList
{
public:
class Iterator
{
public:
Iterator(ServerClusterRegistration * interface, EndpointId endpoint) : mEndpointId(endpoint), mRegistration(interface)
{
if (mRegistration != nullptr)
{
mSpan = interface->serverClusterInterface->GetPaths();
}
AdvanceUntilMatchingEndpoint();
}
Iterator & operator++()
{
if (!mSpan.empty())
{
mSpan = mSpan.SubSpan(1);
}
AdvanceUntilMatchingEndpoint();
return *this;
}
bool operator==(const Iterator & other) const { return mRegistration == other.mRegistration; }
bool operator!=(const Iterator & other) const { return mRegistration != other.mRegistration; }
ClusterId operator*() { return mSpan.begin()->mClusterId; }
private:
const EndpointId mEndpointId;
ServerClusterRegistration * mRegistration;
Span<const ConcreteClusterPath> mSpan;
void AdvanceUntilMatchingEndpoint()
{
while (mRegistration != nullptr)
{
if (mSpan.empty())
{
mRegistration = mRegistration->next;
if (mRegistration != nullptr)
{
mSpan = mRegistration->serverClusterInterface->GetPaths();
}
continue;
}
if (mSpan.begin()->mEndpointId == mEndpointId)
{
return;
}
// need to keep searching
mSpan = mSpan.SubSpan(1);
}
}
};
constexpr ClustersList(ServerClusterRegistration * start, EndpointId endpointId) : mEndpointId(endpointId), mStart(start) {}
Iterator begin() { return { mStart, mEndpointId }; }
Iterator end() { return { nullptr, mEndpointId }; }
private:
const EndpointId mEndpointId;
ServerClusterRegistration * mStart;
};
~SingleEndpointServerClusterRegistry() = default;
/// Add the given entry to the registry.
/// NOTE the requirement of entries to be part of the same endpoint.
///
/// Requirements:
/// - entry MUST NOT be part of any other registration
/// - paths MUST be part of the same endpoint
///
/// - LIFETIME of entry must outlive the Registry (or entry must be unregistered)
///
/// There can be only a single registration for a given `endpointId/clusterId` path.
[[nodiscard]] CHIP_ERROR Register(ServerClusterRegistration & entry);
/// Provides a list of clusters that are registered for the given endpoint.
///
/// ClustersList points inside the internal registrations of the registry, so
/// the list is only valid as long as the registry is not modified.
ClustersList ClustersOnEndpoint(EndpointId endpointId);
/// Unregister all registrations for the given endpoint.
void UnregisterAllFromEndpoint(EndpointId endpointId);
};
} // namespace app
} // namespace chip