-
Notifications
You must be signed in to change notification settings - Fork 2.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add a helper for encoding lists via AttributeValueEncoder. (#10265)
* Add a helper for encoding lists via AttributeValueEncoder. The idea is to not need the whole list in memory at once. * Addressing review comments
- Loading branch information
1 parent
d48d754
commit 4513748
Showing
4 changed files
with
242 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
/* | ||
* | ||
* Copyright (c) 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/data-model/Encode.h> | ||
#include <app/data-model/List.h> // So we can encode lists | ||
#include <lib/core/CHIPTLV.h> | ||
#include <lib/support/CodeUtils.h> | ||
|
||
/** | ||
* Class that encapsulates a TLVWriter and tag that can be provided to a | ||
* consumer so that the consumer can just call Encode and have the tagging | ||
* handled for them. | ||
*/ | ||
namespace chip { | ||
namespace app { | ||
|
||
class TagBoundEncoder | ||
{ | ||
public: | ||
// Initialization with a null TLVWriter is allowed, but attempts to Encode() | ||
// will fail. | ||
TagBoundEncoder(TLV::TLVWriter * aWriter, TLV::Tag aTag) : mWriter(aWriter), mTag(aTag) {} | ||
|
||
template <typename... Ts> | ||
CHIP_ERROR Encode(Ts... aArgs) const | ||
{ | ||
VerifyOrReturnError(mWriter != nullptr, CHIP_ERROR_INCORRECT_STATE); | ||
return DataModel::Encode(*mWriter, mTag, std::forward<Ts>(aArgs)...); | ||
} | ||
|
||
/** | ||
* aCallback is expected to take a const TagBoundEncoder& 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 all items are encoded | ||
* aCallback is expected to return success. | ||
* | ||
* aCallback may not be called. Consumers must not assume it will be | ||
* called. | ||
*/ | ||
template <typename ListGenerator> | ||
CHIP_ERROR EncodeList(ListGenerator aCallback) | ||
{ | ||
VerifyOrReturnError(mWriter != nullptr, CHIP_ERROR_INCORRECT_STATE); | ||
TLV::TLVType outerType; | ||
ReturnErrorOnFailure(mWriter->StartContainer(mTag, TLV::kTLVType_Array, outerType)); | ||
ReturnErrorOnFailure(aCallback(TagBoundEncoder(mWriter, TLV::AnonymousTag))); | ||
return mWriter->EndContainer(outerType); | ||
} | ||
|
||
protected: | ||
TLV::TLVWriter * const mWriter; | ||
|
||
private: | ||
const TLV::Tag mTag; | ||
}; | ||
|
||
} // namespace app | ||
} // namespace chip |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,138 @@ | ||
/* | ||
* | ||
* Copyright (c) 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. | ||
*/ | ||
|
||
/** | ||
* @file | ||
* This file implements unit tests for CommandPathParams | ||
* | ||
*/ | ||
|
||
#include <app/AttributeAccessInterface.h> | ||
#include <app/MessageDef/AttributeDataElement.h> | ||
#include <lib/support/CodeUtils.h> | ||
#include <lib/support/UnitTestRegistration.h> | ||
#include <nlunit-test.h> | ||
|
||
using namespace chip; | ||
using namespace chip::app; | ||
using namespace chip::TLV; | ||
|
||
namespace { | ||
|
||
struct TestSetup | ||
{ | ||
TestSetup(nlTestSuite * aSuite) : encoder(&writer) | ||
{ | ||
writer.Init(buf); | ||
TLVType ignored; | ||
CHIP_ERROR err = writer.StartContainer(AnonymousTag, kTLVType_Structure, ignored); | ||
NL_TEST_ASSERT(aSuite, err == CHIP_NO_ERROR); | ||
} | ||
|
||
AttributeValueEncoder encoder; | ||
uint8_t buf[1024]; | ||
TLVWriter writer; | ||
}; | ||
|
||
// Macro so we get better error reporting in terms of which test failed, because | ||
// the reporting uses __LINE__. | ||
#define VERIFY_BUFFER_STATE(aSuite, aSetup, aExpected) \ | ||
do \ | ||
{ \ | ||
NL_TEST_ASSERT(aSuite, aSetup.writer.GetLengthWritten() == sizeof(aExpected)); \ | ||
NL_TEST_ASSERT(aSuite, memcmp(aSetup.buf, aExpected, sizeof(aExpected)) == 0); \ | ||
} while (0) | ||
|
||
void TestEncodeNothing(nlTestSuite * aSuite, void * aContext) | ||
{ | ||
TestSetup test(aSuite); | ||
// Just have an anonymous struct marker. | ||
const uint8_t expected[] = { 0x15 }; | ||
VERIFY_BUFFER_STATE(aSuite, test, expected); | ||
} | ||
|
||
void TestEncodeBool(nlTestSuite * aSuite, void * aContext) | ||
{ | ||
TestSetup test(aSuite); | ||
CHIP_ERROR err = test.encoder.Encode(true); | ||
NL_TEST_ASSERT(aSuite, err == CHIP_NO_ERROR); | ||
// Anonymous tagged struct. | ||
// Control tag for boolean true with context tag. | ||
// Context tag with value AttributeDataElement::kCsTag_Data. | ||
const uint8_t expected[] = { 0x15, 0x29, 0x02 }; | ||
VERIFY_BUFFER_STATE(aSuite, test, expected); | ||
} | ||
|
||
void TestEncodeListOfBools1(nlTestSuite * aSuite, void * aContext) | ||
{ | ||
TestSetup test(aSuite); | ||
bool list[] = { true, false }; | ||
CHIP_ERROR err = test.encoder.Encode(DataModel::List<bool>(list)); | ||
NL_TEST_ASSERT(aSuite, err == CHIP_NO_ERROR); | ||
// Anonymous tagged struct. | ||
// Control tag for array with context tag. | ||
// Context tag with value AttributeDataElement::kCsTag_Data. | ||
// Control tag for boolean true with anonymous tag. | ||
// Control tag for boolean false with anonymous tag. | ||
// End of list marker. | ||
const uint8_t expected[] = { 0x15, 0x36, 0x02, 0x09, 0x08, 0x18 }; | ||
VERIFY_BUFFER_STATE(aSuite, test, expected); | ||
} | ||
|
||
void TestEncodeListOfBools2(nlTestSuite * aSuite, void * aContext) | ||
{ | ||
TestSetup test(aSuite); | ||
bool list[] = { true, false }; | ||
CHIP_ERROR err = test.encoder.EncodeList([&list](const TagBoundEncoder & encoder) -> CHIP_ERROR { | ||
for (auto & item : list) | ||
{ | ||
ReturnErrorOnFailure(encoder.Encode(item)); | ||
} | ||
return CHIP_NO_ERROR; | ||
}); | ||
NL_TEST_ASSERT(aSuite, err == CHIP_NO_ERROR); | ||
// Anonymous tagged struct. | ||
// Control tag for array with context tag. | ||
// Context tag with value AttributeDataElement::kCsTag_Data. | ||
// Control tag for boolean true with anonymous tag. | ||
// Control tag for boolean false with anonymous tag. | ||
// End of list marker. | ||
const uint8_t expected[] = { 0x15, 0x36, 0x02, 0x09, 0x08, 0x18 }; | ||
VERIFY_BUFFER_STATE(aSuite, test, expected); | ||
} | ||
|
||
#undef VERIFY_STATE | ||
|
||
} // anonymous namespace | ||
|
||
namespace { | ||
const nlTest sTests[] = { NL_TEST_DEF("TestEncodeNothing", TestEncodeNothing), NL_TEST_DEF("TestEncodeBool", TestEncodeBool), | ||
NL_TEST_DEF("TestEncodeListOfBools1", TestEncodeListOfBools1), | ||
NL_TEST_DEF("TestEncodeListOfBools2", TestEncodeListOfBools2), NL_TEST_SENTINEL() }; | ||
} | ||
|
||
int TestAttributeValueEncoder() | ||
{ | ||
nlTestSuite theSuite = { "AttributeValueEncoder", &sTests[0], nullptr, nullptr }; | ||
|
||
nlTestRunner(&theSuite, nullptr); | ||
|
||
return (nlTestRunnerStats(&theSuite)); | ||
} | ||
|
||
CHIP_REGISTER_TEST_SUITE(TestAttributeValueEncoder) |