Conversation
…r rather than per waiter
There was a problem hiding this comment.
Should we add a EC2WaiterCompilationTests.cpp similar to EC2PaginationCompilationTests.cpp that is code generated in smithy to catch any code that doesnt compile or with missing header files.
| @@ -76,10 +80,14 @@ tasks.register("generate-smithy-build") { | |||
| if (filteredServiceList.isEmpty() || c2jName in filteredServiceList) { | |||
| val mockProjectionContents = Node.objectNodeBuilder() | |||
| .withMember("plugins", Node.objectNode() | |||
| .withMember("smithy-cpp-codegen", Node.objectNodeBuilder() | |||
| .withMember("smithy-cpp-codegen-paginators", Node.objectNodeBuilder() | |||
There was a problem hiding this comment.
since we're repeating this projection a lot and might need to add more if we move more c2j stuff to smithy, we could add a helper funtion
fun pluginConfig(c2jMap: String, namespaceMappings: String): ObjectNode {
return Node.objectNode()
.withMember("smithy-cpp-codegen-paginators", Node.objectNodeBuilder()
.withMember("c2jMap", Node.from(c2jMap))
.withMember("namespaceMappings", Node.from(namespaceMappings))
.build())
.withMember("smithy-cpp-codegen-waiters", Node.objectNodeBuilder()
.withMember("c2jMap", Node.from(c2jMap))
.withMember("namespaceMappings", Node.from(namespaceMappings))
.build())
}
that just calls .withMember("plugins", pluginConfig(c2jMapStr, namespaceMappings)).
|
|
||
| template <typename DerivedClient = EC2Client> | ||
| class EC2Waiter { | ||
| public: |
There was a problem hiding this comment.
we need to add user agent metrics similar to PR
| Aws::Utils::WaiterOutcome<Model::DescribeCertificateAuthorityAuditReportOutcome> WaitUntilAuditReportCreated( | ||
| const Model::DescribeCertificateAuthorityAuditReportRequest& request) { | ||
| std::vector<Aws::Utils::Acceptor<Model::DescribeCertificateAuthorityAuditReportOutcome>> acceptors; | ||
| acceptors.push_back( |
There was a problem hiding this comment.
here you dont want to use push_back, you want to use emplace_back and construct the element in-place to avoid a unnecessary constructor. for instance consider the class
class widget {
public:
widget(std::string a, std::string b) { std::cout << "widget()" << std::endl; };
widget(const widget& other) { std::cout << "widget(const widget&)" << std::endl; }
widget(widget&& other) noexcept { std::cout << "widget(widget&&)" << std::endl; }
widget& operator=(const widget& other) {
std::cout << "widget& operator=(const widget&)" << std::endl;
if (this == &other) return *this;
return *this;
}
widget& operator=(widget&& other) noexcept {
std::cout << "widget& operator=(widget&&)" << std::endl;
if (this == &other) return *this;
return *this;
}
};where we call push_back
std::vector<widget> widgets{};
widgets.push_back(widget{"a", "b"});this will output
widget()
widget(widget&&)because we call the constructor, then move construct the item, and infact clang-tidy will give us a warning about this
Clang-Tidy: Use emplace_back instead of push_back
which alludes to this you can instead call emplace back
widgets.emplace_back("a", "b");which will only output
widget()in this case that would look like
acceptors.emplace_back(Aws::Utils::WaiterState::SUCCESS,
Aws::Utils::MatcherType::PATH,
Aws::String("SUCCESS"),
[](const Model::DescribeCertificateAuthorityAuditReportOutcome& outcome, const Aws::Utils::ExpectedValue& expected) {
if (!outcome.IsSuccess()) return false;
const auto& result = outcome.GetResult();
return Model::AuditReportStatusMapper::GetNameForAuditReportStatus(result.GetAuditReportStatus()) == expected.get<Aws::String>();
});| }}); | ||
| acceptors.push_back({Aws::Utils::WaiterState::FAILURE, Aws::Utils::MatcherType::ERROR, Aws::String("AccessDeniedException")}); | ||
|
|
||
| auto operation = [this](const Model::DescribeCertificateAuthorityAuditReportRequest& req) { |
There was a problem hiding this comment.
do we need a intermediate lambda? could we just pass static_cast<DerivedClient*>(this)->DescribeCertificateAuthorityAuditReport to the waiter template?
There was a problem hiding this comment.
Yes. the function is associated with the client object and non-static so we either need a lambda or use std::bind.
| #pragma once | ||
| #include <aws/account/AccountPaginationBase.h> | ||
| #include <aws/account/AccountServiceClientModel.h> | ||
| #include <aws/account/AccountWaiter.h> |
There was a problem hiding this comment.
does AccountWaiter.h exist? compilation should fail if thats the case
| struct Acceptor { | ||
| WaiterState state; | ||
| MatcherType matcher; | ||
| ExpectedValue expected; | ||
| std::function<bool(const OutcomeT&, const ExpectedValue&)> pathMatcher; |
There was a problem hiding this comment.
so i think this goes back to what we talked about a long time ago, which is that MatcherType is tightly coupled with OutcomeT and ExpectedValue. i.e. we change what validation logic is ran in acceptor based on MatcherType. specifically for instance pathMatcher is not use unless MatcherType is PATH_* so it is "wasted space" on a error matcher to have the memory space for pathMatcher.
I think we can use inheritence to get rid of this and more accurately model the "we have different types of acceptors" from a higher view points.
if we had Acceptor as a interface
struct acceptor {
virtual bool accept() = 0;
virtual ~acceptor() = default;
};we can have one "acceptor" implementation per MatcherTypei.e.
class error_acceptor: public acceptor {
public:
error_acceptor() {
// construct for error type
}
virtual bool accept() override {
// test if the error matches
}
};
class path_acceptor: acceptor {
public:
path_acceptor() {
// construct for path type
}
virtual bool accept() override {
// jmes path function matches
}
};when then delegate acceptor type to code gen instead of runtime evaluation of MatcherType.
in waiter generation you could do something like
std::vector<std::unique_ptr<acceptor>> acceptors{};
acceptors.emplace_back(std::make_unique<error_acceptor>());
acceptors.emplace_back(std::make_unique<path_acceptor>());then in Matches you just iterate the list of acceptors and call the vtable for accept
| Shape afterLeft = walkFields(sub.getLeft(), current, model); | ||
| return afterLeft != null ? findFirstListElement(sub.getRight(), afterLeft, model) : null; | ||
| } | ||
| return null; |
There was a problem hiding this comment.
whenever we return null we risk a null pointer exception, returning Optional<Shape> here is what we want to do, and force the caller to handle logic around a missing type.
Issue #, if available:
Description of changes:
Check all that applies:
Check which platforms you have built SDK on to verify the correctness of this PR.
By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.