diff --git a/src/app/AttributeAccessInterface.cpp b/src/app/AttributeAccessInterface.cpp index 0e7723b6059a19..3850128b6bf17f 100644 --- a/src/app/AttributeAccessInterface.cpp +++ b/src/app/AttributeAccessInterface.cpp @@ -69,6 +69,7 @@ CHIP_ERROR AttributeValueEncoder::EncodeEmptyList() // Put an empty array before encoding the first array element for list chunking. AttributeReportBuilder builder; + mPath.mListOp = ConcreteDataAttributePath::ListOperation::ReplaceAll; ReturnErrorOnFailure(builder.PrepareAttribute(mAttributeReportIBsBuilder, mPath, mDataVersion)); ReturnErrorOnFailure(builder.EncodeValue(mAttributeReportIBsBuilder, DataModel::List())); @@ -82,6 +83,9 @@ CHIP_ERROR AttributeValueEncoder::EncodeEmptyList() // revert partial data. mEncodeState.mAllowPartialData = true; + // For all elements in the list, a report with append operation will be generated. This will not be changed during encoding + // of each report since the users cannot access mPath. + mPath.mListOp = ConcreteDataAttributePath::ListOperation::AppendItem; return CHIP_NO_ERROR; } diff --git a/src/app/AttributeAccessInterface.h b/src/app/AttributeAccessInterface.h index f58331c8d1714a..9b58f379d40f67 100644 --- a/src/app/AttributeAccessInterface.h +++ b/src/app/AttributeAccessInterface.h @@ -147,9 +147,9 @@ class AttributeValueEncoder {} /** - * Encode builds a single AttributeReportIB in AttributeReportIBs. - * When we are encoding a single element in the list, the actual path in the report contains a null list index as "append" - * operation. + * Encode a single value. This value will not be chunked; it will either be + * entirely encoded or fail to be encoded. Consumers are allowed to make + * either one call to Encode or one call to EncodeList to handle a read. */ template CHIP_ERROR Encode(Ts &&... aArgs) @@ -158,6 +158,15 @@ class AttributeValueEncoder return EncodeAttributeReportIB(std::forward(aArgs)...); } + /** + * Encode an explicit null value. + */ + CHIP_ERROR EncodeNull() + { + // Doesn't matter what type Nullable we use here. + return Encode(DataModel::Nullable()); + } + /** * aCallback is expected to take a const auto & argument and Encode() on it as many times as needed to encode all the list * elements one by one. If any of those Encode() calls returns failure, aCallback must stop encoding and return failure. When @@ -181,11 +190,7 @@ class AttributeValueEncoder // EmptyList acts as the beginning of the whole array type attribute report. // An empty list is encoded iff both mCurrentEncodingListIndex and mEncodeState.mCurrentEncodingListIndex are invalid // values. After encoding the empty list, mEncodeState.mCurrentEncodingListIndex and mCurrentEncodingListIndex are set to 0. - mPath.mListOp = ConcreteDataAttributePath::ListOperation::ReplaceAll; ReturnErrorOnFailure(EncodeEmptyList()); - // For all elements in the list, a report with append operation will be generated. This will not be changed during encoding - // of each report since the users cannot access mPath. - mPath.mListOp = ConcreteDataAttributePath::ListOperation::AppendItem; ReturnErrorOnFailure(aCallback(ListEncodeHelper(*this))); // The Encode procedure finished without any error, clear the state. mEncodeState = AttributeEncodeState(); @@ -239,12 +244,16 @@ class AttributeValueEncoder } /** - * Actual logic for encoding a single AttributeReportIB in AttributeReportIBs. + * Builds a single AttributeReportIB in AttributeReportIBs. The caller is + * responsible for setting up mPath correctly. + * + * In particular, when we are encoding a single element in the list, mPath + * must indicate a null list index to represent an "append" operation. + * operation. */ template CHIP_ERROR EncodeAttributeReportIB(Ts &&... aArgs) { - mTriedEncode = true; AttributeReportBuilder builder; ReturnErrorOnFailure(builder.PrepareAttribute(mAttributeReportIBsBuilder, mPath, mDataVersion)); @@ -258,6 +267,10 @@ class AttributeValueEncoder * * If internal state indicates we have already encoded the empty list, this function will encode nothing, set * mCurrentEncodingListIndex to 0 and return CHIP_NO_ERROR. + * + * In all cases this function guarantees that mPath.mListOp is AppendItem + * after it returns, because at that point we will be encoding the list + * items. */ CHIP_ERROR EncodeEmptyList();