commit 9106a69434c4b4e2c84f74824e2bb04c6be08e4f
Author: Jacob Evans <jacob.evans@10gen.com>
Date:   Fri Nov 6 18:48:56 2020 -0500

    SERVER-52510 Add additional composition member function to StatusWith for Status-returning functions

diff --git a/src/mongo/base/status_with.h b/src/mongo/base/status_with.h
index b4e2654f81..4fa4576d3e 100644
--- a/src/mongo/base/status_with.h
+++ b/src/mongo/base/status_with.h
@@ -162,54 +162,46 @@ public:
         return _status.isOK();
     }
 
+    template <typename Function, typename QualifiedReferecedStatusWithType>
+    using TRes = StatusWith<std::invoke_result_t<Function, QualifiedReferecedStatusWithType>>;
     /**
      * For any type U returned by a function f, transform creates a StatusWith<U> by either applying
      * the function to the _t member or forwarding the _status. This is the lvalue overload.
      */
     template <typename F>
-    StatusWith<std::invoke_result_t<F&&, T&>> transform(F&& f) & {
-        if (_t)
-            return {std::forward<F>(f)(*_t)};
-        else
-            return {_status};
+    auto transform(F&& f) & {
+        return _t ? TRes<F&&, T&>{std::forward<F>(f)(*_t)} : TRes<F&&, T&>{_status};
     }
-
     /**
      * For any type U returned by a function f, transform creates a StatusWith<U> by either applying
      * the function to the _t member or forwarding the _status. This is the const overload.
      */
     template <typename F>
-    StatusWith<std::invoke_result_t<F&&, const T&>> transform(F&& f) const& {
-        if (_t)
-            return {std::forward<F>(f)(*_t)};
-        else
-            return {_status};
+    auto transform(F&& f) const& {
+        return _t ? TRes<F&&, const T&>{std::forward<F>(f)(*_t)} : TRes<F&&, const T&>{_status};
     }
-
     /**
      * For any type U returned by a function f, transform creates a StatusWith<U> by either applying
      * the function to the _t member or forwarding the _status. This is the rvalue overload.
      */
     template <typename F>
-    StatusWith<std::invoke_result_t<F&&, T&&>> transform(F&& f) && {
-        if (_t)
-            return {std::forward<F>(f)(*std::move(_t))};
-        else
-            return {std::move(_status)};
+    auto transform(F&& f) && {
+        return _t ? TRes<F&&, T&&>{std::forward<F>(f)(*std::move(_t))}
+                  : TRes<F&&, T&&>{std::move(_status)};
     }
-
     /**
      * For any type U returned by a function f, transform creates a StatusWith<U> by either applying
      * the function to the _t member or forwarding the _status. This is the const rvalue overload.
      */
     template <typename F>
-    StatusWith<std::invoke_result_t<F&&, const T&&>> transform(F&& f) const&& {
-        if (_t)
-            return {std::forward<F>(f)(*std::move(_t))};
-        else
-            return {std::move(_status)};
+    auto transform(F&& f) const&& {
+        return _t ? TRes<F&&, const T&&>{std::forward<F>(f)(std::move(*_t))}
+                  : TRes<F&&, const T&&>{std::move(_status)};
     }
 
+    template <typename Function, typename QualifiedReferecedStatusWithType>
+    using ATRes = StatusWith<
+        typename std::invoke_result_t<Function, QualifiedReferecedStatusWithType>::value_type>;
     /**
      * For any type U returned inside a StatusWith<U> by a function f, andThen directly produces a
      * StatusWith<U> by applying the function to the _t member or creates one by forwarding the
@@ -217,13 +209,9 @@ public:
      * type of StatusWith. This is the lvalue overload.
      */
     template <typename F>
-    StatusWith<typename std::invoke_result_t<F&&, T&>::value_type> andThen(F&& f) & {
-        if (_t)
-            return {std::forward<F>(f)(*_t)};
-        else
-            return {_status};
+    auto andThen(F&& f) & {
+        return _t ? ATRes<F&&, T&>{std::forward<F>(f)(*_t)} : ATRes<F&&, T&>{_status};
     }
-
     /**
      * For any type U returned inside a StatusWith<U> by a function f, andThen directly produces a
      * StatusWith<U> by applying the function to the _t member or creates one by forwarding the
@@ -231,13 +219,9 @@ public:
      * type of StatusWith. This is the const overload.
      */
     template <typename F>
-    StatusWith<typename std::invoke_result_t<F&&, const T&>::value_type> andThen(F&& f) const& {
-        if (_t)
-            return {std::forward<F>(f)(*_t)};
-        else
-            return {_status};
+    auto andThen(F&& f) const& {
+        return _t ? ATRes<F&&, const T&>{std::forward<F>(f)(*_t)} : ATRes<F&&, const T&>{_status};
     }
-
     /**
      * For any type U returned inside a StatusWith<U> by a function f, andThen directly produces a
      * StatusWith<U> by applying the function to the _t member or creates one by forwarding the
@@ -245,13 +229,10 @@ public:
      * type of StatusWith. This is the rvalue overload.
      */
     template <typename F>
-    StatusWith<typename std::invoke_result_t<F&&, T&&>::value_type> andThen(F&& f) && {
-        if (_t)
-            return {std::forward<F>(f)(*std::move(_t))};
-        else
-            return {std::move(_status)};
+    auto andThen(F&& f) && {
+        return _t ? ATRes<F&&, T&&>{std::forward<F>(f)(*std::move(_t))}
+                  : ATRes<F&&, T&&>{std::move(_status)};
     }
-
     /**
      * For any type U returned inside a StatusWith<U> by a function f, andThen directly produces a
      * StatusWith<U> by applying the function to the _t member or creates one by forwarding the
@@ -259,11 +240,112 @@ public:
      * type of StatusWith. This is the const rvalue overload.
      */
     template <typename F>
-    StatusWith<typename std::invoke_result_t<F&&, const T&&>::value_type> andThen(F&& f) const&& {
-        if (_t)
-            return {std::forward<F>(f)(*std::move(_t))};
-        else
-            return {std::move(_status)};
+    auto andThen(F&& f) const&& {
+        return _t ? ATRes<F&&, const T&&>{std::forward<F>(f)(std::move(*_t))}
+                  : ATRes<F&&, const T&&>{std::move(_status)};
+    }
+
+    /**
+     * Given a function f producing a Status, asLongAs runs the function on _t if it is present.
+     * If _t is not present _status is returned in a new StatusWith. If the function returns a non-
+     * OK Status, it is returned in a new StatusWith. If the function returns OK, _t is returned in
+     * a new StatusWith. This is the lvalue overload.
+     */
+    template <typename F>
+    auto asLongAs(F&& f) & {
+        if (_t) {
+            if (auto status = std::forward<F>(f)(*_t); status.code() == ErrorCodes::OK)
+                return StatusWith<T>{*_t};
+            else
+                return StatusWith<T>{std::move(status)};
+        } else {
+            return StatusWith<T>{_status};
+        }
+    }
+    /**
+     * Given a function f producing a Status, asLongAs runs the function on _t if it is present.
+     * If _t is not present _status is returned in a new StatusWith. If the function returns a non-
+     * OK Status, it is returned in a new StatusWith. If the function returns OK, _t is returned in
+     * a new StatusWith. This is the const overload.
+     */
+    template <typename F>
+    auto asLongAs(F&& f) const& {
+        if (_t) {
+            if (auto status = std::forward<F>(f)(*_t); status.code() == ErrorCodes::OK)
+                return StatusWith<T>{*_t};
+            else
+                return StatusWith<T>{std::move(status)};
+        } else {
+            return StatusWith<T>{_status};
+        }
+    }
+    /**
+     * Given a function f producing a Status, asLongAs runs the function on _t if it is present.
+     * If _t is not present _status is returned in a new StatusWith. If the function returns a non-
+     * OK Status, it is returned in a new StatusWith. If the function returns OK, _t is returned in
+     * a new StatusWith. This is the rvalue overload.
+     */
+    template <typename F>
+    auto asLongAs(F&& f) && {
+        if (_t) {
+            if (auto status = std::forward<F>(f)(*_t); status.code() == ErrorCodes::OK)
+                return StatusWith<T>{*std::move(_t)};
+            else
+                return StatusWith<T>{std::move(status)};
+        } else {
+            return StatusWith<T>{std::move(_status)};
+        }
+    }
+    /**
+     * Given a function f producing a Status, asLongAs runs the function on _t if it is present.
+     * If _t is not present _status is returned in a new StatusWith. If the function returns a non-
+     * OK Status, it is returned in a new StatusWith. If the function returns OK, _t is returned in
+     * a new StatusWith. This is the const rvalue overload.
+     */
+    template <typename F>
+    auto asLongAs(F&& f) const&& {
+        if (_t) {
+            if (auto status = std::forward<F>(f)(*_t); status.code() == ErrorCodes::OK)
+                return StatusWith<T>{std::move(*_t)};
+            else
+                return StatusWith<T>{std::move(status)};
+        } else {
+            return StatusWith<T>{std::move(_status)};
+        }
+    }
+
+    /**
+     * Given a function f producing a Status, finally runs the function on _t if it is present,
+     * returning the result. If _t is not present _status is returned. This is the lvalue overload.
+     */
+    template <typename F>
+    auto finally(F&& f) & {
+        return _t ? std::forward<F>(f)(*_t) : _status;
+    }
+    /**
+     * Given a function f producing a Status, finally runs the function on _t if it is present,
+     * returning the result. If _t is not present _status is returned. This is the const overload.
+     */
+    template <typename F>
+    auto finally(F&& f) const& {
+        return _t ? std::forward<F>(f)(*_t) : _status;
+    }
+    /**
+     * Given a function f producing a Status, finally runs the function on _t if it is present,
+     * returning the result. If _t is not present _status is returned. This is the rvalue overload.
+     */
+    template <typename F>
+    auto finally(F&& f) && {
+        return _t ? std::forward<F>(f)(*std::move(_t)) : std::move(_status);
+    }
+    /**
+     * Given a function f producing a Status, finally runs the function on _t if it is present,
+     * returning the result. If _t is not present _status is returned. This is the const rvalue
+     * overload.
+     */
+    template <typename F>
+    auto finally(F&& f) const&& {
+        return _t ? std::forward<F>(f)(std::move(*_t)) : std::move(_status);
     }
 
     /**
diff --git a/src/mongo/base/status_with_test.cpp b/src/mongo/base/status_with_test.cpp
index d115815564..d2f50efb46 100644
--- a/src/mongo/base/status_with_test.cpp
+++ b/src/mongo/base/status_with_test.cpp
@@ -92,7 +92,7 @@ TEST(StatusWith, ignoreTest) {
     [] { return StatusWith(false); }().getStatus().ignore();
 }
 
-TEST(StatusWith, MonadicTestLValue) {
+TEST(StatusWith, TransformTestLValue) {
     {
         auto from = StatusWith<int>{3};
         auto to = from.transform([](auto&& i) { return static_cast<double>(i); });
@@ -107,6 +107,9 @@ TEST(StatusWith, MonadicTestLValue) {
                       "StatusWith::transform returns incorrect type");
         ASSERT_EQ(Status(ErrorCodes::IllegalOperation, "broke the law"), to.getStatus());
     }
+}
+
+TEST(StatusWith, AndThenTestLValue) {
     {
         auto from = StatusWith<int>{3};
         auto to = from.andThen([](auto&& i) { return StatusWith<double>{static_cast<double>(i)}; });
@@ -141,7 +144,77 @@ TEST(StatusWith, MonadicTestLValue) {
     }
 }
 
-TEST(StatusWith, MonadicTestConst) {
+TEST(StatusWith, AsLongAsTestLValue) {
+    {
+        auto from = StatusWith<int>{3};
+        auto to = from.asLongAs([](auto&& i) { return Status::OK(); });
+        static_assert(std::is_same_v<StatusWith<int>, decltype(to)>,
+                      "StatusWith::asLongAs returns incorrect type");
+        ASSERT_EQ(3, to.getValue());
+    }
+    {
+        auto from = StatusWith<int>{Status{ErrorCodes::IllegalOperation, "broke the law"}};
+        auto to = from.asLongAs([](auto&& i) { return Status::OK(); });
+        static_assert(std::is_same_v<StatusWith<int>, decltype(to)>,
+                      "StatusWith::asLongAs returns incorrect type");
+        ASSERT_EQ(Status(ErrorCodes::IllegalOperation, "broke the law"), to.getStatus());
+    }
+    {
+        auto from = StatusWith<int>{3};
+        auto to = from.asLongAs([](auto&& i) {
+            return Status{ErrorCodes::BadValue, "lousy value"};
+        });
+        static_assert(std::is_same_v<StatusWith<int>, decltype(to)>,
+                      "StatusWith::asLongAs returns incorrect type");
+        ASSERT_EQ(Status(ErrorCodes::BadValue, "lousy value"), to.getStatus());
+    }
+    {
+        auto from = StatusWith<int>{Status{ErrorCodes::IllegalOperation, "broke the law"}};
+        auto to = from.asLongAs([](auto&& i) {
+            return Status{ErrorCodes::BadValue, "lousy value"};
+        });
+        static_assert(std::is_same_v<StatusWith<int>, decltype(to)>,
+                      "StatusWith::asLongAs returns incorrect type");
+        ASSERT_EQ(Status(ErrorCodes::IllegalOperation, "broke the law"), to.getStatus());
+    }
+}
+
+TEST(StatusWith, FinallyTestLValue) {
+    {
+        auto from = StatusWith<int>{3};
+        auto to = from.finally([](auto&& i) { return Status::OK(); });
+        static_assert(std::is_same_v<Status, decltype(to)>,
+                      "StatusWith::finally returns incorrect type");
+        ASSERT(to.isOK());
+    }
+    {
+        auto from = StatusWith<int>{Status{ErrorCodes::IllegalOperation, "broke the law"}};
+        auto to = from.finally([](auto&& i) { return Status::OK(); });
+        static_assert(std::is_same_v<Status, decltype(to)>,
+                      "StatusWith::finally returns incorrect type");
+        ASSERT_EQ(Status(ErrorCodes::IllegalOperation, "broke the law"), to);
+    }
+    {
+        auto from = StatusWith<int>{3};
+        auto to = from.finally([](auto&& i) {
+            return Status{ErrorCodes::BadValue, "lousy value"};
+        });
+        static_assert(std::is_same_v<Status, decltype(to)>,
+                      "StatusWith::finally returns incorrect type");
+        ASSERT_EQ(Status(ErrorCodes::BadValue, "lousy value"), to);
+    }
+    {
+        auto from = StatusWith<int>{Status{ErrorCodes::IllegalOperation, "broke the law"}};
+        auto to = from.finally([](auto&& i) {
+            return Status{ErrorCodes::BadValue, "lousy value"};
+        });
+        static_assert(std::is_same_v<Status, decltype(to)>,
+                      "StatusWith::finally returns incorrect type");
+        ASSERT_EQ(Status(ErrorCodes::IllegalOperation, "broke the law"), to);
+    }
+}
+
+TEST(StatusWith, TransformTestConst) {
     {
         const auto from = StatusWith<int>{3};
         auto to = from.transform([](auto&& i) { return static_cast<double>(i); });
@@ -156,6 +229,9 @@ TEST(StatusWith, MonadicTestConst) {
                       "StatusWith::transform returns incorrect type");
         ASSERT_EQ(Status(ErrorCodes::IllegalOperation, "broke the law"), to.getStatus());
     }
+}
+
+TEST(StatusWith, AndThenTestConst) {
     {
         const auto from = StatusWith<int>{3};
         auto to = from.andThen([](auto&& i) { return StatusWith<double>{static_cast<double>(i)}; });
@@ -190,7 +266,77 @@ TEST(StatusWith, MonadicTestConst) {
     }
 }
 
-TEST(StatusWith, MonadicTestRValue) {
+TEST(StatusWith, AsLongAsTestConst) {
+    {
+        const auto from = StatusWith<int>{3};
+        auto to = from.asLongAs([](auto&& i) { return Status::OK(); });
+        static_assert(std::is_same_v<StatusWith<int>, decltype(to)>,
+                      "StatusWith::asLongAs returns incorrect type");
+        ASSERT_EQ(3, to.getValue());
+    }
+    {
+        const auto from = StatusWith<int>{Status{ErrorCodes::IllegalOperation, "broke the law"}};
+        auto to = from.asLongAs([](auto&& i) { return Status::OK(); });
+        static_assert(std::is_same_v<StatusWith<int>, decltype(to)>,
+                      "StatusWith::asLongAs returns incorrect type");
+        ASSERT_EQ(Status(ErrorCodes::IllegalOperation, "broke the law"), to.getStatus());
+    }
+    {
+        const auto from = StatusWith<int>{3};
+        auto to = from.asLongAs([](auto&& i) {
+            return Status{ErrorCodes::BadValue, "lousy value"};
+        });
+        static_assert(std::is_same_v<StatusWith<int>, decltype(to)>,
+                      "StatusWith::asLongAs returns incorrect type");
+        ASSERT_EQ(Status(ErrorCodes::BadValue, "lousy value"), to.getStatus());
+    }
+    {
+        const auto from = StatusWith<int>{Status{ErrorCodes::IllegalOperation, "broke the law"}};
+        auto to = from.asLongAs([](auto&& i) {
+            return Status{ErrorCodes::BadValue, "lousy value"};
+        });
+        static_assert(std::is_same_v<StatusWith<int>, decltype(to)>,
+                      "StatusWith::asLongAs returns incorrect type");
+        ASSERT_EQ(Status(ErrorCodes::IllegalOperation, "broke the law"), to.getStatus());
+    }
+}
+
+TEST(StatusWith, FinallyTestConst) {
+    {
+        const auto from = StatusWith<int>{3};
+        auto to = from.finally([](auto&& i) { return Status::OK(); });
+        static_assert(std::is_same_v<Status, decltype(to)>,
+                      "StatusWith::finally returns incorrect type");
+        ASSERT(to.isOK());
+    }
+    {
+        const auto from = StatusWith<int>{Status{ErrorCodes::IllegalOperation, "broke the law"}};
+        auto to = from.finally([](auto&& i) { return Status::OK(); });
+        static_assert(std::is_same_v<Status, decltype(to)>,
+                      "StatusWith::finally returns incorrect type");
+        ASSERT_EQ(Status(ErrorCodes::IllegalOperation, "broke the law"), to);
+    }
+    {
+        const auto from = StatusWith<int>{3};
+        auto to = from.finally([](auto&& i) {
+            return Status{ErrorCodes::BadValue, "lousy value"};
+        });
+        static_assert(std::is_same_v<Status, decltype(to)>,
+                      "StatusWith::finally returns incorrect type");
+        ASSERT_EQ(Status(ErrorCodes::BadValue, "lousy value"), to);
+    }
+    {
+        const auto from = StatusWith<int>{Status{ErrorCodes::IllegalOperation, "broke the law"}};
+        auto to = from.finally([](auto&& i) {
+            return Status{ErrorCodes::BadValue, "lousy value"};
+        });
+        static_assert(std::is_same_v<Status, decltype(to)>,
+                      "StatusWith::finally returns incorrect type");
+        ASSERT_EQ(Status(ErrorCodes::IllegalOperation, "broke the law"), to);
+    }
+}
+
+TEST(StatusWith, TransformTestRValue) {
     {
         auto from = StatusWith<int>{3};
         auto to = std::move(from).transform([](auto&& i) { return static_cast<double>(i); });
@@ -205,6 +351,9 @@ TEST(StatusWith, MonadicTestRValue) {
                       "StatusWith::transform returns incorrect type");
         ASSERT_EQ(Status(ErrorCodes::IllegalOperation, "broke the law"), to.getStatus());
     }
+}
+
+TEST(StatusWith, AndThenTestRValue) {
     {
         auto from = StatusWith<int>{3};
         auto to = std::move(from).andThen(
@@ -241,7 +390,77 @@ TEST(StatusWith, MonadicTestRValue) {
     }
 }
 
-TEST(StatusWith, MonadicTestConstRValue) {
+TEST(StatusWith, AsLongAsTestRValue) {
+    {
+        auto from = StatusWith<int>{3};
+        auto to = std::move(from).asLongAs([](auto&& i) { return Status::OK(); });
+        static_assert(std::is_same_v<StatusWith<int>, decltype(to)>,
+                      "StatusWith::asLongAs returns incorrect type");
+        ASSERT_EQ(3, to.getValue());
+    }
+    {
+        auto from = StatusWith<int>{Status{ErrorCodes::IllegalOperation, "broke the law"}};
+        auto to = std::move(from).asLongAs([](auto&& i) { return Status::OK(); });
+        static_assert(std::is_same_v<StatusWith<int>, decltype(to)>,
+                      "StatusWith::asLongAs returns incorrect type");
+        ASSERT_EQ(Status(ErrorCodes::IllegalOperation, "broke the law"), to.getStatus());
+    }
+    {
+        auto from = StatusWith<int>{3};
+        auto to = std::move(from).asLongAs([](auto&& i) {
+            return Status{ErrorCodes::BadValue, "lousy value"};
+        });
+        static_assert(std::is_same_v<StatusWith<int>, decltype(to)>,
+                      "StatusWith::asLongAs returns incorrect type");
+        ASSERT_EQ(Status(ErrorCodes::BadValue, "lousy value"), to.getStatus());
+    }
+    {
+        auto from = StatusWith<int>{Status{ErrorCodes::IllegalOperation, "broke the law"}};
+        auto to = std::move(from).asLongAs([](auto&& i) {
+            return Status{ErrorCodes::BadValue, "lousy value"};
+        });
+        static_assert(std::is_same_v<StatusWith<int>, decltype(to)>,
+                      "StatusWith::asLongAs returns incorrect type");
+        ASSERT_EQ(Status(ErrorCodes::IllegalOperation, "broke the law"), to.getStatus());
+    }
+}
+
+TEST(StatusWith, FinallyTestRValue) {
+    {
+        auto from = StatusWith<int>{3};
+        auto to = std::move(from).finally([](auto&& i) { return Status::OK(); });
+        static_assert(std::is_same_v<Status, decltype(to)>,
+                      "StatusWith::finally returns incorrect type");
+        ASSERT(to.isOK());
+    }
+    {
+        auto from = StatusWith<int>{Status{ErrorCodes::IllegalOperation, "broke the law"}};
+        auto to = std::move(from).finally([](auto&& i) { return Status::OK(); });
+        static_assert(std::is_same_v<Status, decltype(to)>,
+                      "StatusWith::finally returns incorrect type");
+        ASSERT_EQ(Status(ErrorCodes::IllegalOperation, "broke the law"), to);
+    }
+    {
+        auto from = StatusWith<int>{3};
+        auto to = std::move(from).finally([](auto&& i) {
+            return Status{ErrorCodes::BadValue, "lousy value"};
+        });
+        static_assert(std::is_same_v<Status, decltype(to)>,
+                      "StatusWith::finally returns incorrect type");
+        ASSERT_EQ(Status(ErrorCodes::BadValue, "lousy value"), to);
+    }
+    {
+        auto from = StatusWith<int>{Status{ErrorCodes::IllegalOperation, "broke the law"}};
+        auto to = std::move(from).finally([](auto&& i) {
+            return Status{ErrorCodes::BadValue, "lousy value"};
+        });
+        static_assert(std::is_same_v<Status, decltype(to)>,
+                      "StatusWith::finally returns incorrect type");
+        ASSERT_EQ(Status(ErrorCodes::IllegalOperation, "broke the law"), to);
+    }
+}
+
+TEST(StatusWith, TransformTestConstRValue) {
     {
         const auto from = StatusWith<int>{3};
         auto to = std::move(from).transform([](auto&& i) { return static_cast<double>(i); });
@@ -256,6 +475,9 @@ TEST(StatusWith, MonadicTestConstRValue) {
                       "StatusWith::transform returns incorrect type");
         ASSERT_EQ(Status(ErrorCodes::IllegalOperation, "broke the law"), to.getStatus());
     }
+}
+
+TEST(StatusWith, AndThenTestConstRValue) {
     {
         const auto from = StatusWith<int>{3};
         auto to = std::move(from).andThen(
@@ -292,7 +514,77 @@ TEST(StatusWith, MonadicTestConstRValue) {
     }
 }
 
-TEST(StatusWith, Overload) {
+TEST(StatusWith, AsLongAsTestConstRValue) {
+    {
+        const auto from = StatusWith<int>{3};
+        auto to = std::move(from).asLongAs([](auto&& i) { return Status::OK(); });
+        static_assert(std::is_same_v<StatusWith<int>, decltype(to)>,
+                      "StatusWith::asLongAs returns incorrect type");
+        ASSERT_EQ(3, to.getValue());
+    }
+    {
+        const auto from = StatusWith<int>{Status{ErrorCodes::IllegalOperation, "broke the law"}};
+        auto to = std::move(from).asLongAs([](auto&& i) { return Status::OK(); });
+        static_assert(std::is_same_v<StatusWith<int>, decltype(to)>,
+                      "StatusWith::asLongAs returns incorrect type");
+        ASSERT_EQ(Status(ErrorCodes::IllegalOperation, "broke the law"), to.getStatus());
+    }
+    {
+        const auto from = StatusWith<int>{3};
+        auto to = std::move(from).asLongAs([](auto&& i) {
+            return Status{ErrorCodes::BadValue, "lousy value"};
+        });
+        static_assert(std::is_same_v<StatusWith<int>, decltype(to)>,
+                      "StatusWith::asLongAs returns incorrect type");
+        ASSERT_EQ(Status(ErrorCodes::BadValue, "lousy value"), to.getStatus());
+    }
+    {
+        const auto from = StatusWith<int>{Status{ErrorCodes::IllegalOperation, "broke the law"}};
+        auto to = std::move(from).asLongAs([](auto&& i) {
+            return Status{ErrorCodes::BadValue, "lousy value"};
+        });
+        static_assert(std::is_same_v<StatusWith<int>, decltype(to)>,
+                      "StatusWith::asLongAs returns incorrect type");
+        ASSERT_EQ(Status(ErrorCodes::IllegalOperation, "broke the law"), to.getStatus());
+    }
+}
+
+TEST(StatusWith, FinallyTestConstRValue) {
+    {
+        const auto from = StatusWith<int>{3};
+        auto to = std::move(from).finally([](auto&& i) { return Status::OK(); });
+        static_assert(std::is_same_v<Status, decltype(to)>,
+                      "StatusWith::finally returns incorrect type");
+        ASSERT(to.isOK());
+    }
+    {
+        const auto from = StatusWith<int>{Status{ErrorCodes::IllegalOperation, "broke the law"}};
+        auto to = std::move(from).finally([](auto&& i) { return Status::OK(); });
+        static_assert(std::is_same_v<Status, decltype(to)>,
+                      "StatusWith::finally returns incorrect type");
+        ASSERT_EQ(Status(ErrorCodes::IllegalOperation, "broke the law"), to);
+    }
+    {
+        const auto from = StatusWith<int>{3};
+        auto to = std::move(from).finally([](auto&& i) {
+            return Status{ErrorCodes::BadValue, "lousy value"};
+        });
+        static_assert(std::is_same_v<Status, decltype(to)>,
+                      "StatusWith::finally returns incorrect type");
+        ASSERT_EQ(Status(ErrorCodes::BadValue, "lousy value"), to);
+    }
+    {
+        const auto from = StatusWith<int>{Status{ErrorCodes::IllegalOperation, "broke the law"}};
+        auto to = std::move(from).finally([](auto&& i) {
+            return Status{ErrorCodes::BadValue, "lousy value"};
+        });
+        static_assert(std::is_same_v<Status, decltype(to)>,
+                      "StatusWith::finally returns incorrect type");
+        ASSERT_EQ(Status(ErrorCodes::IllegalOperation, "broke the law"), to);
+    }
+}
+
+TEST(StatusWith, TransformOverload) {
     struct LValue {};
     struct Const {};
     struct RValue {};
@@ -350,7 +642,78 @@ TEST(StatusWith, Overload) {
         auto operator()(const int&&) const&& {
             return std::pair{ConstRValue{}, ConstRValue{}};
         }
-    } transformFuncs;
+    } funcs;
+
+    {
+        auto in = StatusWith<int>{3};
+        static_assert(
+            std::is_same_v<StatusWith<std::pair<LValue, LValue>>, decltype(in.transform(funcs))>,
+            "StatusWith::transform returns incorrect type");
+        static_assert(std::is_same_v<StatusWith<std::pair<LValue, Const>>,
+                                     decltype(in.transform(std::as_const(funcs)))>,
+                      "StatusWith::transform returns incorrect type");
+        static_assert(std::is_same_v<StatusWith<std::pair<LValue, RValue>>,
+                                     decltype(in.transform(std::move(funcs)))>,
+                      "StatusWith::transform returns incorrect type");
+        static_assert(std::is_same_v<StatusWith<std::pair<LValue, ConstRValue>>,
+                                     decltype(in.transform(std::move(std::as_const(funcs))))>,
+                      "StatusWith::transform returns incorrect type");
+    }
+    {
+        const auto in = StatusWith<int>{3};
+        static_assert(
+            std::is_same_v<StatusWith<std::pair<Const, LValue>>, decltype(in.transform(funcs))>,
+            "StatusWith::transform returns incorrect type");
+        static_assert(std::is_same_v<StatusWith<std::pair<Const, Const>>,
+                                     decltype(in.transform(std::as_const(funcs)))>,
+                      "StatusWith::transform returns incorrect type");
+        static_assert(std::is_same_v<StatusWith<std::pair<Const, RValue>>,
+                                     decltype(in.transform(std::move(funcs)))>,
+                      "StatusWith::transform returns incorrect type");
+        static_assert(std::is_same_v<StatusWith<std::pair<Const, ConstRValue>>,
+                                     decltype(in.transform(std::move(std::as_const(funcs))))>,
+                      "StatusWith::transform returns incorrect type");
+    }
+    {
+        auto in = StatusWith<int>{3};
+        static_assert(std::is_same_v<StatusWith<std::pair<RValue, LValue>>,
+                                     decltype(std::move(in).transform(funcs))>,
+                      "StatusWith::transform returns incorrect type");
+        static_assert(std::is_same_v<StatusWith<std::pair<RValue, Const>>,
+                                     decltype(std::move(in).transform(std::as_const(funcs)))>,
+                      "StatusWith::transform returns incorrect type");
+        static_assert(std::is_same_v<StatusWith<std::pair<RValue, RValue>>,
+                                     decltype(std::move(in).transform(std::move(funcs)))>,
+                      "StatusWith::transform returns incorrect type");
+        static_assert(
+            std::is_same_v<StatusWith<std::pair<RValue, ConstRValue>>,
+                           decltype(std::move(in).transform(std::move(std::as_const(funcs))))>,
+            "StatusWith::transform returns incorrect type");
+    }
+    {
+        const auto in = StatusWith<int>{3};
+        static_assert(std::is_same_v<StatusWith<std::pair<ConstRValue, LValue>>,
+                                     decltype(std::move(in).transform(funcs))>,
+                      "StatusWith::transform returns incorrect type");
+        static_assert(std::is_same_v<StatusWith<std::pair<ConstRValue, Const>>,
+                                     decltype(std::move(in).transform(std::as_const(funcs)))>,
+                      "StatusWith::transform returns incorrect type");
+        static_assert(std::is_same_v<StatusWith<std::pair<ConstRValue, RValue>>,
+                                     decltype(std::move(in).transform(std::move(funcs)))>,
+                      "StatusWith::transform returns incorrect type");
+        static_assert(
+            std::is_same_v<StatusWith<std::pair<ConstRValue, ConstRValue>>,
+                           decltype(std::move(in).transform(std::move(std::as_const(funcs))))>,
+            "StatusWith::transform returns incorrect type");
+    }
+}
+
+TEST(StatusWith, AndThenOverload) {
+    struct LValue {};
+    struct Const {};
+    struct RValue {};
+    struct ConstRValue {};
+
     struct {
         auto operator()(int&) & {
             return StatusWith{std::pair{LValue{}, LValue{}}};
@@ -403,124 +766,278 @@ TEST(StatusWith, Overload) {
         auto operator()(const int&&) const&& {
             return StatusWith{std::pair{ConstRValue{}, ConstRValue{}}};
         }
-    } andThenFuncs;
+    } funcs;
+
     {
         auto in = StatusWith<int>{3};
-        static_assert(std::is_same_v<StatusWith<std::pair<LValue, LValue>>,
-                                     decltype(in.transform(transformFuncs))>,
-                      "StatusWith::transform returns incorrect type");
-        static_assert(std::is_same_v<StatusWith<std::pair<LValue, LValue>>,
-                                     decltype(in.andThen(andThenFuncs))>,
-                      "StatusWith::andThen returns incorrect type");
-        static_assert(std::is_same_v<StatusWith<std::pair<LValue, Const>>,
-                                     decltype(in.transform(std::as_const(transformFuncs)))>,
-                      "StatusWith::transform returns incorrect type");
+        static_assert(
+            std::is_same_v<StatusWith<std::pair<LValue, LValue>>, decltype(in.andThen(funcs))>,
+            "StatusWith::andThen returns incorrect type");
         static_assert(std::is_same_v<StatusWith<std::pair<LValue, Const>>,
-                                     decltype(in.andThen(std::as_const(andThenFuncs)))>,
+                                     decltype(in.andThen(std::as_const(funcs)))>,
                       "StatusWith::andThen returns incorrect type");
         static_assert(std::is_same_v<StatusWith<std::pair<LValue, RValue>>,
-                                     decltype(in.transform(std::move(transformFuncs)))>,
-                      "StatusWith::transform returns incorrect type");
-        static_assert(std::is_same_v<StatusWith<std::pair<LValue, RValue>>,
-                                     decltype(in.andThen(std::move(andThenFuncs)))>,
+                                     decltype(in.andThen(std::move(funcs)))>,
                       "StatusWith::andThen returns incorrect type");
-        static_assert(
-            std::is_same_v<StatusWith<std::pair<LValue, ConstRValue>>,
-                           decltype(in.transform(std::move(std::as_const(transformFuncs))))>,
-            "StatusWith::transform returns incorrect type");
         static_assert(std::is_same_v<StatusWith<std::pair<LValue, ConstRValue>>,
-                                     decltype(in.andThen(std::move(std::as_const(andThenFuncs))))>,
+                                     decltype(in.andThen(std::move(std::as_const(funcs))))>,
                       "StatusWith::andThen returns incorrect type");
     }
     {
         const auto in = StatusWith<int>{3};
-        static_assert(std::is_same_v<StatusWith<std::pair<Const, LValue>>,
-                                     decltype(in.transform(transformFuncs))>,
-                      "StatusWith::transform returns incorrect type");
-        static_assert(std::is_same_v<StatusWith<std::pair<Const, LValue>>,
-                                     decltype(in.andThen(andThenFuncs))>,
-                      "StatusWith::andThen returns incorrect type");
-        static_assert(std::is_same_v<StatusWith<std::pair<Const, Const>>,
-                                     decltype(in.transform(std::as_const(transformFuncs)))>,
-                      "StatusWith::transform returns incorrect type");
+        static_assert(
+            std::is_same_v<StatusWith<std::pair<Const, LValue>>, decltype(in.andThen(funcs))>,
+            "StatusWith::andThen returns incorrect type");
         static_assert(std::is_same_v<StatusWith<std::pair<Const, Const>>,
-                                     decltype(in.andThen(std::as_const(andThenFuncs)))>,
+                                     decltype(in.andThen(std::as_const(funcs)))>,
                       "StatusWith::andThen returns incorrect type");
         static_assert(std::is_same_v<StatusWith<std::pair<Const, RValue>>,
-                                     decltype(in.transform(std::move(transformFuncs)))>,
-                      "StatusWith::transform returns incorrect type");
-        static_assert(std::is_same_v<StatusWith<std::pair<Const, RValue>>,
-                                     decltype(in.andThen(std::move(andThenFuncs)))>,
+                                     decltype(in.andThen(std::move(funcs)))>,
                       "StatusWith::andThen returns incorrect type");
-        static_assert(
-            std::is_same_v<StatusWith<std::pair<Const, ConstRValue>>,
-                           decltype(in.transform(std::move(std::as_const(transformFuncs))))>,
-            "StatusWith::transform returns incorrect type");
         static_assert(std::is_same_v<StatusWith<std::pair<Const, ConstRValue>>,
-                                     decltype(in.andThen(std::move(std::as_const(andThenFuncs))))>,
+                                     decltype(in.andThen(std::move(std::as_const(funcs))))>,
                       "StatusWith::andThen returns incorrect type");
     }
     {
         auto in = StatusWith<int>{3};
         static_assert(std::is_same_v<StatusWith<std::pair<RValue, LValue>>,
-                                     decltype(std::move(in).transform(transformFuncs))>,
-                      "StatusWith::transform returns incorrect type");
-        static_assert(std::is_same_v<StatusWith<std::pair<RValue, LValue>>,
-                                     decltype(std::move(in).andThen(andThenFuncs))>,
+                                     decltype(std::move(in).andThen(funcs))>,
                       "StatusWith::andThen returns incorrect type");
-        static_assert(
-            std::is_same_v<StatusWith<std::pair<RValue, Const>>,
-                           decltype(std::move(in).transform(std::as_const(transformFuncs)))>,
-            "StatusWith::transform returns incorrect type");
         static_assert(std::is_same_v<StatusWith<std::pair<RValue, Const>>,
-                                     decltype(std::move(in).andThen(std::as_const(andThenFuncs)))>,
+                                     decltype(std::move(in).andThen(std::as_const(funcs)))>,
                       "StatusWith::andThen returns incorrect type");
         static_assert(std::is_same_v<StatusWith<std::pair<RValue, RValue>>,
-                                     decltype(std::move(in).transform(std::move(transformFuncs)))>,
-                      "StatusWith::transform returns incorrect type");
-        static_assert(std::is_same_v<StatusWith<std::pair<RValue, RValue>>,
-                                     decltype(std::move(in).andThen(std::move(andThenFuncs)))>,
+                                     decltype(std::move(in).andThen(std::move(funcs)))>,
                       "StatusWith::andThen returns incorrect type");
-        static_assert(std::is_same_v<StatusWith<std::pair<RValue, ConstRValue>>,
-                                     decltype(std::move(in).transform(
-                                         std::move(std::as_const(transformFuncs))))>,
-                      "StatusWith::transform returns incorrect type");
         static_assert(
             std::is_same_v<StatusWith<std::pair<RValue, ConstRValue>>,
-                           decltype(std::move(in).andThen(std::move(std::as_const(andThenFuncs))))>,
+                           decltype(std::move(in).andThen(std::move(std::as_const(funcs))))>,
             "StatusWith::andThen returns incorrect type");
     }
     {
         const auto in = StatusWith<int>{3};
         static_assert(std::is_same_v<StatusWith<std::pair<ConstRValue, LValue>>,
-                                     decltype(std::move(in).transform(transformFuncs))>,
-                      "StatusWith::transform returns incorrect type");
-        static_assert(std::is_same_v<StatusWith<std::pair<ConstRValue, LValue>>,
-                                     decltype(std::move(in).andThen(andThenFuncs))>,
+                                     decltype(std::move(in).andThen(funcs))>,
                       "StatusWith::andThen returns incorrect type");
-        static_assert(
-            std::is_same_v<StatusWith<std::pair<ConstRValue, Const>>,
-                           decltype(std::move(in).transform(std::as_const(transformFuncs)))>,
-            "StatusWith::transform returns incorrect type");
         static_assert(std::is_same_v<StatusWith<std::pair<ConstRValue, Const>>,
-                                     decltype(std::move(in).andThen(std::as_const(andThenFuncs)))>,
+                                     decltype(std::move(in).andThen(std::as_const(funcs)))>,
                       "StatusWith::andThen returns incorrect type");
         static_assert(std::is_same_v<StatusWith<std::pair<ConstRValue, RValue>>,
-                                     decltype(std::move(in).transform(std::move(transformFuncs)))>,
-                      "StatusWith::transform returns incorrect type");
-        static_assert(std::is_same_v<StatusWith<std::pair<ConstRValue, RValue>>,
-                                     decltype(std::move(in).andThen(std::move(andThenFuncs)))>,
+                                     decltype(std::move(in).andThen(std::move(funcs)))>,
                       "StatusWith::andThen returns incorrect type");
-        static_assert(std::is_same_v<StatusWith<std::pair<ConstRValue, ConstRValue>>,
-                                     decltype(std::move(in).transform(
-                                         std::move(std::as_const(transformFuncs))))>,
-                      "StatusWith::transform returns incorrect type");
         static_assert(
             std::is_same_v<StatusWith<std::pair<ConstRValue, ConstRValue>>,
-                           decltype(std::move(in).andThen(std::move(std::as_const(andThenFuncs))))>,
+                           decltype(std::move(in).andThen(std::move(std::as_const(funcs))))>,
             "StatusWith::andThen returns incorrect type");
     }
 }
 
+TEST(StatusWith, AsLongAsOverload) {
+    using namespace std::string_literals;
+    struct LValue {};
+    struct Const {};
+    struct RValue {};
+    struct ConstRValue {};
+
+    struct {
+        auto operator()(int&) & {
+            return Status{ErrorCodes::TypeMismatch, "lvalue arg, lvalue function"};
+        }
+        auto operator()(const int&) & {
+            return Status{ErrorCodes::TypeMismatch, "const arg, lvalue function"};
+        }
+        auto operator()(int&&) & {
+            return Status{ErrorCodes::TypeMismatch, "rvalue arg, lvalue function"};
+        }
+        auto operator()(const int&&) & {
+            return Status{ErrorCodes::TypeMismatch, "const rvalue arg, lvalue function"};
+        }
+
+        auto operator()(int&) const& {
+            return Status{ErrorCodes::TypeMismatch, "lvalue arg, const function"};
+        }
+        auto operator()(const int&) const& {
+            return Status{ErrorCodes::TypeMismatch, "const arg, const function"};
+        }
+        auto operator()(int&&) const& {
+            return Status{ErrorCodes::TypeMismatch, "rvalue arg, const function"};
+        }
+        auto operator()(const int&&) const& {
+            return Status{ErrorCodes::TypeMismatch, "const rvalue arg, const function"};
+        }
+
+        auto operator()(int&) && {
+            return Status{ErrorCodes::TypeMismatch, "lvalue arg, rvalue function"};
+        }
+        auto operator()(const int&) && {
+            return Status{ErrorCodes::TypeMismatch, "const arg, rvalue function"};
+        }
+        auto operator()(int&&) && {
+            return Status{ErrorCodes::TypeMismatch, "rvalue arg, rvalue function"};
+        }
+        auto operator()(const int&&) && {
+            return Status{ErrorCodes::TypeMismatch, "const rvalue arg, rvalue function"};
+        }
+
+        auto operator()(int&) const&& {
+            return Status{ErrorCodes::TypeMismatch, "lvalue arg, const rvalue function"};
+        }
+        auto operator()(const int&) const&& {
+            return Status{ErrorCodes::TypeMismatch, "const arg, const rvalue function"};
+        }
+        auto operator()(int&&) const&& {
+            return Status{ErrorCodes::TypeMismatch, "rvalue arg, const rvalue function"};
+        }
+        auto operator()(const int&&) const&& {
+            return Status{ErrorCodes::TypeMismatch, "const rvalue arg, const rvalue function"};
+        }
+    } funcs;
+
+    {
+        auto in = StatusWith<int>{3};
+        ASSERT_EQ("lvalue arg, lvalue function"s, in.asLongAs(funcs).getStatus().reason());
+        ASSERT_EQ("lvalue arg, const function"s,
+                  in.asLongAs(std::as_const(funcs)).getStatus().reason());
+        ASSERT_EQ("lvalue arg, rvalue function"s,
+                  in.asLongAs(std::move(funcs)).getStatus().reason());
+        ASSERT_EQ("lvalue arg, const rvalue function"s,
+                  in.asLongAs(std::move(std::as_const(funcs))).getStatus().reason());
+    }
+    {
+        const auto in = StatusWith<int>{3};
+        ASSERT_EQ("const arg, lvalue function"s, in.asLongAs(funcs).getStatus().reason());
+        ASSERT_EQ("const arg, const function"s,
+                  in.asLongAs(std::as_const(funcs)).getStatus().reason());
+        ASSERT_EQ("const arg, rvalue function"s,
+                  in.asLongAs(std::move(funcs)).getStatus().reason());
+        ASSERT_EQ("const arg, const rvalue function"s,
+                  in.asLongAs(std::move(std::as_const(funcs))).getStatus().reason());
+    }
+    {
+        auto in = StatusWith<int>{3};
+        // These call the provided function with an lvalue since the rvalue is reserved for moving
+        // the _t value if the function returns Status::OK.
+        ASSERT_EQ("lvalue arg, lvalue function"s,
+                  std::move(in).asLongAs(funcs).getStatus().reason());
+        ASSERT_EQ("lvalue arg, const function"s,
+                  std::move(in).asLongAs(std::as_const(funcs)).getStatus().reason());
+        ASSERT_EQ("lvalue arg, rvalue function"s,
+                  std::move(in).asLongAs(std::move(funcs)).getStatus().reason());
+        ASSERT_EQ("lvalue arg, const rvalue function"s,
+                  std::move(in).asLongAs(std::move(std::as_const(funcs))).getStatus().reason());
+    }
+    {
+        const auto in = StatusWith<int>{3};
+        // These call the provided function with an lvalue since the rvalue is reserved for moving
+        // the _t value if the function returns Status::OK.
+        ASSERT_EQ("const arg, lvalue function"s,
+                  std::move(in).asLongAs(funcs).getStatus().reason());
+        ASSERT_EQ("const arg, const function"s,
+                  std::move(in).asLongAs(std::as_const(funcs)).getStatus().reason());
+        ASSERT_EQ("const arg, rvalue function"s,
+                  std::move(in).asLongAs(std::move(funcs)).getStatus().reason());
+        ASSERT_EQ("const arg, const rvalue function"s,
+                  std::move(in).asLongAs(std::move(std::as_const(funcs))).getStatus().reason());
+    }
+}
+
+TEST(StatusWith, FinallyOverload) {
+    using namespace std::string_literals;
+    struct LValue {};
+    struct Const {};
+    struct RValue {};
+    struct ConstRValue {};
+
+    struct {
+        auto operator()(int&) & {
+            return Status{ErrorCodes::TypeMismatch, "lvalue arg, lvalue function"};
+        }
+        auto operator()(const int&) & {
+            return Status{ErrorCodes::TypeMismatch, "const arg, lvalue function"};
+        }
+        auto operator()(int&&) & {
+            return Status{ErrorCodes::TypeMismatch, "rvalue arg, lvalue function"};
+        }
+        auto operator()(const int&&) & {
+            return Status{ErrorCodes::TypeMismatch, "const rvalue arg, lvalue function"};
+        }
+
+        auto operator()(int&) const& {
+            return Status{ErrorCodes::TypeMismatch, "lvalue arg, const function"};
+        }
+        auto operator()(const int&) const& {
+            return Status{ErrorCodes::TypeMismatch, "const arg, const function"};
+        }
+        auto operator()(int&&) const& {
+            return Status{ErrorCodes::TypeMismatch, "rvalue arg, const function"};
+        }
+        auto operator()(const int&&) const& {
+            return Status{ErrorCodes::TypeMismatch, "const rvalue arg, const function"};
+        }
+
+        auto operator()(int&) && {
+            return Status{ErrorCodes::TypeMismatch, "lvalue arg, rvalue function"};
+        }
+        auto operator()(const int&) && {
+            return Status{ErrorCodes::TypeMismatch, "const arg, rvalue function"};
+        }
+        auto operator()(int&&) && {
+            return Status{ErrorCodes::TypeMismatch, "rvalue arg, rvalue function"};
+        }
+        auto operator()(const int&&) && {
+            return Status{ErrorCodes::TypeMismatch, "const rvalue arg, rvalue function"};
+        }
+
+        auto operator()(int&) const&& {
+            return Status{ErrorCodes::TypeMismatch, "lvalue arg, const rvalue function"};
+        }
+        auto operator()(const int&) const&& {
+            return Status{ErrorCodes::TypeMismatch, "const arg, const rvalue function"};
+        }
+        auto operator()(int&&) const&& {
+            return Status{ErrorCodes::TypeMismatch, "rvalue arg, const rvalue function"};
+        }
+        auto operator()(const int&&) const&& {
+            return Status{ErrorCodes::TypeMismatch, "const rvalue arg, const rvalue function"};
+        }
+    } funcs;
+
+    {
+        auto in = StatusWith<int>{3};
+        ASSERT_EQ("lvalue arg, lvalue function"s, in.finally(funcs).reason());
+        ASSERT_EQ("lvalue arg, const function"s, in.finally(std::as_const(funcs)).reason());
+        ASSERT_EQ("lvalue arg, rvalue function"s, in.finally(std::move(funcs)).reason());
+        ASSERT_EQ("lvalue arg, const rvalue function"s,
+                  in.finally(std::move(std::as_const(funcs))).reason());
+    }
+    {
+        const auto in = StatusWith<int>{3};
+        ASSERT_EQ("const arg, lvalue function"s, in.finally(funcs).reason());
+        ASSERT_EQ("const arg, const function"s, in.finally(std::as_const(funcs)).reason());
+        ASSERT_EQ("const arg, rvalue function"s, in.finally(std::move(funcs)).reason());
+        ASSERT_EQ("const arg, const rvalue function"s,
+                  in.finally(std::move(std::as_const(funcs))).reason());
+    }
+    {
+        auto in = StatusWith<int>{3};
+        ASSERT_EQ("rvalue arg, lvalue function"s, std::move(in).finally(funcs).reason());
+        ASSERT_EQ("rvalue arg, const function"s,
+                  std::move(in).finally(std::as_const(funcs)).reason());
+        ASSERT_EQ("rvalue arg, rvalue function"s, std::move(in).finally(std::move(funcs)).reason());
+        ASSERT_EQ("rvalue arg, const rvalue function"s,
+                  std::move(in).finally(std::move(std::as_const(funcs))).reason());
+    }
+    {
+        const auto in = StatusWith<int>{3};
+        ASSERT_EQ("const rvalue arg, lvalue function"s, std::move(in).finally(funcs).reason());
+        ASSERT_EQ("const rvalue arg, const function"s,
+                  std::move(in).finally(std::as_const(funcs)).reason());
+        ASSERT_EQ("const rvalue arg, rvalue function"s,
+                  std::move(in).finally(std::move(funcs)).reason());
+        ASSERT_EQ("const rvalue arg, const rvalue function"s,
+                  std::move(in).finally(std::move(std::as_const(funcs))).reason());
+    }
+}
+
 }  // namespace
 }  // namespace mongo
