diff options
author | 2024-05-30 21:01:26 -0400 | |
---|---|---|
committer | 2024-06-11 11:16:24 -0400 | |
commit | 1f39c3d3ceaa140c480acbb23504490c2f49450e (patch) | |
tree | e96ffeebdcba5ea1c5fdfa94514ca45eccd043ad | |
parent | 677ba5a2beda0734633d2dc548338bed0d467258 (diff) |
FTL: Add FTL_EXPECT
Like FTL_TRY, FTL_EXPECT unwraps T for Expected<T, E> or does an early
out on error, but it bails out with E instead of Expected<T, E>.
Fix a line in the Expected.Try test to call the intended helper.
Bug: 185536303
Test: ftl_test
Change-Id: I238ae2978ff606c5c035e9791496c2b20729ca7f
-rw-r--r-- | include/ftl/expected.h | 30 | ||||
-rw-r--r-- | libs/ftl/expected_test.cpp | 39 |
2 files changed, 63 insertions, 6 deletions
diff --git a/include/ftl/expected.h b/include/ftl/expected.h index 57448dc1e0..7e765c5681 100644 --- a/include/ftl/expected.h +++ b/include/ftl/expected.h @@ -69,6 +69,36 @@ exp_.value(); \ }) +// Given an expression `expr` that evaluates to an ftl::Expected<T, E> result (R for short), +// FTL_EXPECT unwraps T out of R, or bails out of the enclosing function F if R has an error E. +// While FTL_TRY bails out with R, FTL_EXPECT bails out with E, which is useful when F does not +// need to propagate R because T is not relevant to the caller. +// +// Example usage: +// +// using StringExp = ftl::Expected<std::string, std::errc>; +// +// std::errc repeat(StringExp exp, std::string& out) { +// const std::string str = FTL_EXPECT(exp); +// out = str + str; +// return std::errc::operation_in_progress; +// } +// +// std::string str; +// assert(std::errc::operation_in_progress == repeat(StringExp("ha"s), str)); +// assert("haha"s == str); +// assert(std::errc::bad_message == repeat(ftl::Unexpected(std::errc::bad_message), str)); +// assert("haha"s == str); +// +#define FTL_EXPECT(expr) \ + ({ \ + auto exp_ = (expr); \ + if (!exp_.has_value()) { \ + return std::move(exp_.error()); \ + } \ + exp_.value(); \ + }) + namespace android::ftl { // Superset of base::expected<T, E> with monadic operations. diff --git a/libs/ftl/expected_test.cpp b/libs/ftl/expected_test.cpp index 9b7f017df3..d5b1d7ea8f 100644 --- a/libs/ftl/expected_test.cpp +++ b/libs/ftl/expected_test.cpp @@ -79,16 +79,28 @@ TEST(Expected, ValueOpt) { namespace { -IntExp increment(IntExp exp) { +IntExp increment_try(IntExp exp) { const int i = FTL_TRY(exp); return IntExp(i + 1); } -StringExp repeat(StringExp exp) { +std::errc increment_expect(IntExp exp, int& out) { + const int i = FTL_EXPECT(exp); + out = i + 1; + return std::errc::operation_in_progress; +} + +StringExp repeat_try(StringExp exp) { const std::string str = FTL_TRY(exp); return StringExp(str + str); } +std::errc repeat_expect(StringExp exp, std::string& out) { + const std::string str = FTL_EXPECT(exp); + out = str + str; + return std::errc::operation_in_progress; +} + void uppercase(char& c, ftl::Optional<char> opt) { c = std::toupper(FTL_TRY(std::move(opt).ok_or(ftl::Unit()))); } @@ -97,13 +109,13 @@ void uppercase(char& c, ftl::Optional<char> opt) { // Keep in sync with example usage in header file. TEST(Expected, Try) { - EXPECT_EQ(IntExp(100), increment(IntExp(99))); - EXPECT_TRUE(repeat(ftl::Unexpected(std::errc::value_too_large)).has_error([](std::errc e) { + EXPECT_EQ(IntExp(100), increment_try(IntExp(99))); + EXPECT_TRUE(increment_try(ftl::Unexpected(std::errc::value_too_large)).has_error([](std::errc e) { return e == std::errc::value_too_large; })); - EXPECT_EQ(StringExp("haha"s), repeat(StringExp("ha"s))); - EXPECT_TRUE(repeat(ftl::Unexpected(std::errc::bad_message)).has_error([](std::errc e) { + EXPECT_EQ(StringExp("haha"s), repeat_try(StringExp("ha"s))); + EXPECT_TRUE(repeat_try(ftl::Unexpected(std::errc::bad_message)).has_error([](std::errc e) { return e == std::errc::bad_message; })); @@ -115,4 +127,19 @@ TEST(Expected, Try) { EXPECT_EQ(c, 'A'); } +TEST(Expected, Expect) { + int i = 0; + EXPECT_EQ(std::errc::operation_in_progress, increment_expect(IntExp(99), i)); + EXPECT_EQ(100, i); + EXPECT_EQ(std::errc::value_too_large, + increment_expect(ftl::Unexpected(std::errc::value_too_large), i)); + EXPECT_EQ(100, i); + + std::string str; + EXPECT_EQ(std::errc::operation_in_progress, repeat_expect(StringExp("ha"s), str)); + EXPECT_EQ("haha"s, str); + EXPECT_EQ(std::errc::bad_message, repeat_expect(ftl::Unexpected(std::errc::bad_message), str)); + EXPECT_EQ("haha"s, str); +} + } // namespace android::test |