pw_result: add PW_TRY_ASSIGN support
Adds PW_TRY_ASSIGN to pw::Result<T>.
Change-Id: I7cc73c14f7f36bc048098abd17f543b8ddf252af
Reviewed-on: https://pigweed-review.googlesource.com/c/pigweed/pigweed/+/41900
Reviewed-by: Wyatt Hepler <hepler@google.com>
Pigweed-Auto-Submit: Ewout van Bekkum <ewout@google.com>
Commit-Queue: Auto-Submit <auto-submit@pigweed.google.com.iam.gserviceaccount.com>
diff --git a/pw_result/BUILD b/pw_result/BUILD
index e2d6b59..7566d23 100644
--- a/pw_result/BUILD
+++ b/pw_result/BUILD
@@ -39,6 +39,7 @@
srcs = ["result_test.cc"],
deps = [
":pw_result",
+ "//pw_status",
"//pw_unit_test",
],
)
diff --git a/pw_result/BUILD.gn b/pw_result/BUILD.gn
index 31cd575..dc4f2e7 100644
--- a/pw_result/BUILD.gn
+++ b/pw_result/BUILD.gn
@@ -37,7 +37,10 @@
}
pw_test("result_test") {
- deps = [ ":pw_result" ]
+ deps = [
+ ":pw_result",
+ dir_pw_status,
+ ]
sources = [ "result_test.cc" ]
}
diff --git a/pw_result/docs.rst b/pw_result/docs.rst
index bfc37cd..b628bbd 100644
--- a/pw_result/docs.rst
+++ b/pw_result/docs.rst
@@ -7,6 +7,44 @@
data when the status is OK. This is meant for returning lightweight result
types or references to larger results.
+``pw::Result`` is compatible with ``PW_TRY`` and ``PW_TRY_ASSIGN``, for example:
+
+.. code-block:: cpp
+
+ #include "pw_status/try.h"
+ #include "pw_result/result.h"
+
+ pw::Result<int> GetAnswer(); // Example function.
+
+ pw::Status UseAnswer() {
+ const pw::Result<int> answer = GetAnswer();
+ if (!answer.ok()) {
+ return answer.status();
+ }
+ if (answer.value() == 42) {
+ WhatWasTheUltimateQuestion();
+ }
+ return pw::OkStatus();
+ }
+
+ pw::Status UseAnswerWithTry() {
+ const pw::Result<int> answer = GetAnswer();
+ PW_TRY(answer.status());
+ if (answer.value() == 42) {
+ WhatWasTheUltimateQuestion();
+ }
+ return pw::OkStatus();
+ }
+
+ pw::Status UseAnswerWithTryAssign() {
+ PW_TRY_ASSIGN(const int answer, GetAnswer());
+ if (answer == 42) {
+ WhatWasTheUltimateQuestion();
+ }
+ return pw::OkStatus();
+ }
+
+
.. warning::
Be careful not to use larger types by value as this can quickly consume
diff --git a/pw_result/public/pw_result/result.h b/pw_result/public/pw_result/result.h
index e529344..6c93697 100644
--- a/pw_result/public/pw_result/result.h
+++ b/pw_result/public/pw_result/result.h
@@ -14,6 +14,7 @@
#pragma once
#include <algorithm>
+#include <utility>
#include "pw_assert/light.h"
#include "pw_status/status.h"
@@ -23,6 +24,9 @@
// A Result represents the result of an operation which can fail. It is a
// convenient wrapper around returning a Status alongside some data when the
// status is OK.
+//
+// TODO(pwbug/363): Refactor pw::Result to properly support non-default move
+// and/or copy assignment operators and/or constructors.
template <typename T>
class Result {
public:
@@ -96,4 +100,17 @@
Status status_;
};
+namespace internal {
+
+template <typename T>
+constexpr Status ConvertToStatus(const Result<T>& result) {
+ return result.status();
+}
+
+template <typename T>
+constexpr T ConvertToValue(Result<T>& result) {
+ return std::move(result.value());
+}
+
+} // namespace internal
} // namespace pw
diff --git a/pw_result/result_test.cc b/pw_result/result_test.cc
index e9095f5..6642cf3 100644
--- a/pw_result/result_test.cc
+++ b/pw_result/result_test.cc
@@ -15,6 +15,7 @@
#include "pw_result/result.h"
#include "gtest/gtest.h"
+#include "pw_status/try.h"
namespace pw {
namespace {
@@ -72,5 +73,28 @@
EXPECT_EQ(res.status(), Status::InvalidArgument());
}
+Result<bool> ReturnResult(Result<bool> result) { return result; }
+
+Status TryResultAssign(Result<bool> result) {
+ PW_TRY_ASSIGN(const bool value, ReturnResult(result));
+
+ // Any status other than OK should have already returned.
+ EXPECT_EQ(result.status(), OkStatus());
+ EXPECT_EQ(value, result.value());
+ return result.status();
+}
+
+// TODO(pwbug/363): Once pw::Result has been refactored to properly support
+// non-default move and/or copy assignment operators and/or constructors, we
+// should add explicit tests to confirm this is properly handled by
+// PW_TRY_ASSIGN.
+TEST(Result, TryAssign) {
+ EXPECT_EQ(TryResultAssign(Status::Cancelled()), Status::Cancelled());
+ EXPECT_EQ(TryResultAssign(Status::DataLoss()), Status::DataLoss());
+ EXPECT_EQ(TryResultAssign(Status::Unimplemented()), Status::Unimplemented());
+ EXPECT_EQ(TryResultAssign(false), OkStatus());
+ EXPECT_EQ(TryResultAssign(true), OkStatus());
+}
+
} // namespace
} // namespace pw
diff --git a/pw_status/public/pw_status/try.h b/pw_status/public/pw_status/try.h
index 76e7a19..38ab26e 100644
--- a/pw_status/public/pw_status/try.h
+++ b/pw_status/public/pw_status/try.h
@@ -13,6 +13,8 @@
// the License.
#pragma once
+#include <utility>
+
#include "pw_status/status.h"
#include "pw_status/status_with_size.h"
@@ -35,7 +37,7 @@
if (!result.ok()) { \
return ::pw::internal::ConvertToStatus(result); \
} \
- lhs = std::move(result.size())
+ lhs = ::pw::internal::ConvertToValue(result);
// Macro for cleanly working with Status or StatusWithSize objects in functions
// that return StatusWithSize.
@@ -59,6 +61,10 @@
return status_with_size.status();
}
+constexpr size_t ConvertToValue(StatusWithSize status_with_size) {
+ return status_with_size.size();
+}
+
constexpr StatusWithSize ConvertToStatusWithSize(Status status) {
return StatusWithSize(status, 0);
}