blob: 4acc96f138c50edca515ba16acf55086c16185b3 [file] [log] [blame]
/*
*
* Copyright (c) 2020-2021 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-common/zap-generated/cluster-enums-check.h>
#include <app/ConcreteAttributePath.h>
#include <app/data-model/Nullable.h>
#include <lib/core/CHIPError.h>
#include <lib/core/CHIPSafeCasts.h>
#include <lib/core/Optional.h>
#include <lib/core/TLV.h>
#include <protocols/interaction_model/Constants.h>
namespace chip {
namespace app {
namespace Clusters {
static auto __attribute__((unused)) EnsureKnownEnumValue(chip::VendorId val)
{
return val;
}
} // namespace Clusters
namespace DataModel {
//
// Decode
//
template <typename X, typename std::enable_if_t<std::is_integral<X>::value, int> = 0>
CHIP_ERROR Decode(TLV::TLVReader & reader, X & x)
{
return reader.Get(x);
}
template <typename X, typename std::enable_if_t<std::is_floating_point<X>::value, int> = 0>
CHIP_ERROR Decode(TLV::TLVReader & reader, X & x)
{
return reader.Get(x);
}
template <typename X, typename std::enable_if_t<std::is_enum<X>::value, int> = 0>
CHIP_ERROR Decode(TLV::TLVReader & reader, X & x)
{
ReturnErrorOnFailure(reader.Get(x));
x = Clusters::EnsureKnownEnumValue(x);
return CHIP_NO_ERROR;
}
template <typename X>
CHIP_ERROR Decode(TLV::TLVReader & reader, BitFlags<X> & x)
{
return reader.Get(x);
}
//
// @brief
//
// Decodes an octet string that is expected at the positioned reader.
//
// The passed in ByteSpan is ignored and updated to point directly into
// the buffer backing the reader.
//
inline CHIP_ERROR Decode(TLV::TLVReader & reader, ByteSpan & x)
{
VerifyOrReturnError(reader.GetType() == TLV::kTLVType_ByteString, CHIP_ERROR_UNEXPECTED_TLV_ELEMENT);
return reader.Get(x);
}
//
// @brief
//
// Decodes a UTF-8 string that is expected at the positioned reader.
//
// The passed in char Span is ignored and updated to point directly into
// the buffer backing the reader.
//
inline CHIP_ERROR Decode(TLV::TLVReader & reader, Span<const char> & x)
{
return reader.Get(x);
}
/*
* @brief
*
* This specific variant that decodes cluster objects (like structs, commands, events) from TLV
* depends on the presence of a Decode method on the object to present. The signature of that method
* is as follows:
*
* CHIP_ERROR <Object>::Decode(TLVReader &reader);
*
*/
template <typename X,
typename std::enable_if_t<
std::is_class<X>::value &&
std::is_same<decltype(std::declval<X>().Decode(std::declval<TLV::TLVReader &>())), CHIP_ERROR>::value,
X> * = nullptr>
CHIP_ERROR Decode(TLV::TLVReader & reader, X & x)
{
return x.Decode(reader);
}
/*
* @brief
*
* This specific variant decodes from TLV a cluster object that contains all attributes encapsulated within a single, monolithic
* cluster object.
*
* Each attribute in the cluster is decoded based on the provided ConcreteAttributePath. The TLVReader is to be positioned right on
* the data value for the specified attribute.
*
* This API depends on the presence of a Decode method on the object. The signature of that method
* is as follows:
*
* CHIP_ERROR <Object>::Decode(TLVReader &reader, ConcreteAttributePath &path);
*
*/
template <
typename X,
typename std::enable_if_t<std::is_class<X>::value &&
std::is_same<decltype(std::declval<X>().Decode(std::declval<TLV::TLVReader &>(),
std::declval<const ConcreteAttributePath &>())),
CHIP_ERROR>::value,
X> * = nullptr>
CHIP_ERROR Decode(TLV::TLVReader & reader, const ConcreteAttributePath & path, X & x)
{
return x.Decode(reader, path);
}
/*
* @brief
*
* Decodes an optional value (struct field, command field, event field).
*/
template <typename X>
CHIP_ERROR Decode(TLV::TLVReader & reader, Optional<X> & x)
{
// If we are calling this, it means we found the right tag, so just decode
// the item.
return Decode(reader, x.Emplace());
}
/*
* @brief
*
* Decodes a nullable value.
*/
template <typename X>
CHIP_ERROR Decode(TLV::TLVReader & reader, Nullable<X> & x)
{
if (reader.GetType() == TLV::kTLVType_Null)
{
x.SetNull();
return CHIP_NO_ERROR;
}
// We have a value; decode it.
ReturnErrorOnFailure(Decode(reader, x.SetNonNull()));
if (!x.ExistingValueInEncodableRange())
{
return CHIP_IM_GLOBAL_STATUS(ConstraintError);
}
return CHIP_NO_ERROR;
}
} // namespace DataModel
} // namespace app
} // namespace chip