Extract Try to top-level
authorYedidya Feldblum <yfeldblum@fb.com>
Thu, 19 May 2016 09:20:24 +0000 (02:20 -0700)
committerFacebook Github Bot 6 <facebook-github-bot-6-bot@fb.com>
Thu, 19 May 2016 09:23:43 +0000 (02:23 -0700)
Summary:
[Folly] Extract `Try` to top-level.

It was in `folly/futures/`, but this diff moves it to `folly/`.

It is needed for futures, but it is are more general than futures and can be used separately.

Use `folly/Try.h` instead of `folly/futures/Try.h`.

Also fixes up all `#include` sites:

    hg grep -lw folly/futures/Try | xargs perl -pi -e 's,\bfolly/futures/Try\b,folly/Try,g'

Reviewed By: markisaa

Differential Revision: D3309908

fbshipit-source-id: cdf13f0ac0b0e36aa07e0f1d04870d06500c5874

17 files changed:
folly/Makefile.am
folly/Try-inl.h [new file with mode: 0644]
folly/Try.h [new file with mode: 0644]
folly/fibers/AddTasks.h
folly/fibers/FiberManager-inl.h
folly/fibers/FiberManager.h
folly/fibers/Promise.h
folly/futures/Future.h
folly/futures/Promise.h
folly/futures/README.md
folly/futures/Try-inl.h [deleted file]
folly/futures/Try.h [deleted file]
folly/futures/detail/Core.h
folly/futures/test/HeaderCompileTest.cpp
folly/futures/test/TryTest.cpp [deleted file]
folly/test/Makefile.am
folly/test/TryTest.cpp [new file with mode: 0644]

index 1cc7a2ee193d099097fa89ff35b41a0d93977e95..1b28ff7ff88d336826c1ad18c04aa8a83874b691 100644 (file)
@@ -173,8 +173,6 @@ nobase_follyinclude_HEADERS = \
        futures/SharedPromise-inl.h \
        futures/ThreadWheelTimekeeper.h \
        futures/Timekeeper.h \
        futures/SharedPromise-inl.h \
        futures/ThreadWheelTimekeeper.h \
        futures/Timekeeper.h \
-       futures/Try-inl.h \
-       futures/Try.h \
        futures/detail/Core.h \
        futures/detail/FSM.h \
        futures/detail/Types.h \
        futures/detail/Core.h \
        futures/detail/FSM.h \
        futures/detail/Types.h \
@@ -345,6 +343,8 @@ nobase_follyinclude_HEADERS = \
        ThreadName.h \
        TimeoutQueue.h \
        Traits.h \
        ThreadName.h \
        TimeoutQueue.h \
        Traits.h \
+       Try-inl.h \
+       Try.h \
        Unicode.h \
        Function.h \
        Unit.h \
        Unicode.h \
        Function.h \
        Unit.h \
diff --git a/folly/Try-inl.h b/folly/Try-inl.h
new file mode 100644 (file)
index 0000000..ba988e3
--- /dev/null
@@ -0,0 +1,176 @@
+/*
+ * Copyright 2016 Facebook, Inc.
+ *
+ * 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 <stdexcept>
+
+namespace folly {
+
+template <class T>
+Try<T>::Try(Try<T>&& t) noexcept : contains_(t.contains_) {
+  if (contains_ == Contains::VALUE) {
+    new (&value_)T(std::move(t.value_));
+  } else if (contains_ == Contains::EXCEPTION) {
+    new (&e_)std::unique_ptr<exception_wrapper>(std::move(t.e_));
+  }
+}
+
+template <class T>
+template <class T2>
+Try<T>::Try(typename std::enable_if<std::is_same<Unit, T2>::value,
+                                    Try<void> const&>::type t)
+    : contains_(Contains::NOTHING) {
+  if (t.hasValue()) {
+    contains_ = Contains::VALUE;
+    new (&value_) T();
+  } else if (t.hasException()) {
+    contains_ = Contains::EXCEPTION;
+    new (&e_) std::unique_ptr<exception_wrapper>(
+        folly::make_unique<exception_wrapper>(t.exception()));
+  }
+}
+
+template <class T>
+Try<T>& Try<T>::operator=(Try<T>&& t) noexcept {
+  if (this == &t) {
+    return *this;
+  }
+
+  this->~Try();
+  contains_ = t.contains_;
+  if (contains_ == Contains::VALUE) {
+    new (&value_)T(std::move(t.value_));
+  } else if (contains_ == Contains::EXCEPTION) {
+    new (&e_)std::unique_ptr<exception_wrapper>(std::move(t.e_));
+  }
+  return *this;
+}
+
+template <class T>
+Try<T>::Try(const Try<T>& t) {
+  static_assert(
+      std::is_copy_constructible<T>::value,
+      "T must be copyable for Try<T> to be copyable");
+  contains_ = t.contains_;
+  if (contains_ == Contains::VALUE) {
+    new (&value_)T(t.value_);
+  } else if (contains_ == Contains::EXCEPTION) {
+    new (&e_)std::unique_ptr<exception_wrapper>();
+    e_ = folly::make_unique<exception_wrapper>(*(t.e_));
+  }
+}
+
+template <class T>
+Try<T>& Try<T>::operator=(const Try<T>& t) {
+  static_assert(
+      std::is_copy_constructible<T>::value,
+      "T must be copyable for Try<T> to be copyable");
+  this->~Try();
+  contains_ = t.contains_;
+  if (contains_ == Contains::VALUE) {
+    new (&value_)T(t.value_);
+  } else if (contains_ == Contains::EXCEPTION) {
+    new (&e_)std::unique_ptr<exception_wrapper>();
+    e_ = folly::make_unique<exception_wrapper>(*(t.e_));
+  }
+  return *this;
+}
+
+template <class T>
+Try<T>::~Try() {
+  if (LIKELY(contains_ == Contains::VALUE)) {
+    value_.~T();
+  } else if (UNLIKELY(contains_ == Contains::EXCEPTION)) {
+    e_.~unique_ptr<exception_wrapper>();
+  }
+}
+
+template <class T>
+T& Try<T>::value() & {
+  throwIfFailed();
+  return value_;
+}
+
+template <class T>
+T&& Try<T>::value() && {
+  throwIfFailed();
+  return std::move(value_);
+}
+
+template <class T>
+const T& Try<T>::value() const & {
+  throwIfFailed();
+  return value_;
+}
+
+template <class T>
+void Try<T>::throwIfFailed() const {
+  if (contains_ != Contains::VALUE) {
+    if (contains_ == Contains::EXCEPTION) {
+      e_->throwException();
+    } else {
+      throw UsingUninitializedTry();
+    }
+  }
+}
+
+void Try<void>::throwIfFailed() const {
+  if (!hasValue_) {
+    e_->throwException();
+  }
+}
+
+template <typename T>
+inline T moveFromTry(Try<T>& t) {
+  return std::move(t.value());
+}
+
+inline void moveFromTry(Try<void>& t) {
+  return t.value();
+}
+
+template <typename F>
+typename std::enable_if<
+  !std::is_same<typename std::result_of<F()>::type, void>::value,
+  Try<typename std::result_of<F()>::type>>::type
+makeTryWith(F&& f) {
+  typedef typename std::result_of<F()>::type ResultType;
+  try {
+    return Try<ResultType>(f());
+  } catch (std::exception& e) {
+    return Try<ResultType>(exception_wrapper(std::current_exception(), e));
+  } catch (...) {
+    return Try<ResultType>(exception_wrapper(std::current_exception()));
+  }
+}
+
+template <typename F>
+typename std::enable_if<
+  std::is_same<typename std::result_of<F()>::type, void>::value,
+  Try<void>>::type
+makeTryWith(F&& f) {
+  try {
+    f();
+    return Try<void>();
+  } catch (std::exception& e) {
+    return Try<void>(exception_wrapper(std::current_exception(), e));
+  } catch (...) {
+    return Try<void>(exception_wrapper(std::current_exception()));
+  }
+}
+
+} // folly
diff --git a/folly/Try.h b/folly/Try.h
new file mode 100644 (file)
index 0000000..edfe6a7
--- /dev/null
@@ -0,0 +1,423 @@
+/*
+ * Copyright 2016 Facebook, Inc.
+ *
+ * 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 <type_traits>
+#include <exception>
+#include <algorithm>
+#include <folly/ExceptionWrapper.h>
+#include <folly/Likely.h>
+#include <folly/Memory.h>
+#include <folly/Portability.h>
+#include <folly/Unit.h>
+
+namespace folly {
+
+class TryException : public std::exception {
+ public:
+  explicit TryException(std::string message_arg) noexcept
+      : message(std::move(message_arg)) {}
+
+  const char* what() const noexcept override {
+    return message.c_str();
+  }
+
+  bool operator==(const TryException& other) const noexcept {
+    return other.message == this->message;
+  }
+
+  bool operator!=(const TryException& other) const noexcept {
+    return !(*this == other);
+  }
+
+ protected:
+  std::string message;
+};
+
+class UsingUninitializedTry : public TryException {
+ public:
+  UsingUninitializedTry() noexcept : TryException("Using unitialized try") {}
+};
+
+/*
+ * Try<T> is a wrapper that contains either an instance of T, an exception, or
+ * nothing. Exceptions are stored as exception_wrappers so that the user can
+ * minimize rethrows if so desired.
+ *
+ * To represent success or a captured exception, use Try<Unit>.
+ */
+template <class T>
+class Try {
+  static_assert(!std::is_reference<T>::value,
+                "Try may not be used with reference types");
+
+  enum class Contains {
+    VALUE,
+    EXCEPTION,
+    NOTHING,
+  };
+
+ public:
+  /*
+   * The value type for the Try
+   */
+  typedef T element_type;
+
+  /*
+   * Construct an empty Try
+   */
+  Try() : contains_(Contains::NOTHING) {}
+
+  /*
+   * Construct a Try with a value by copy
+   *
+   * @param v The value to copy in
+   */
+  explicit Try(const T& v) : contains_(Contains::VALUE), value_(v) {}
+
+  /*
+   * Construct a Try with a value by move
+   *
+   * @param v The value to move in
+   */
+  explicit Try(T&& v) : contains_(Contains::VALUE), value_(std::move(v)) {}
+
+  /// Implicit conversion from Try<void> to Try<Unit>
+  template <class T2 = T>
+  /* implicit */
+  Try(typename std::enable_if<std::is_same<Unit, T2>::value,
+                              Try<void> const&>::type t);
+
+  /*
+   * Construct a Try with an exception_wrapper
+   *
+   * @param e The exception_wrapper
+   */
+  explicit Try(exception_wrapper e)
+    : contains_(Contains::EXCEPTION),
+      e_(folly::make_unique<exception_wrapper>(std::move(e))) {}
+
+  /*
+   * DEPRECATED
+   * Construct a Try with an exception_pointer
+   *
+   * @param ep The exception_pointer. Will be rethrown.
+   */
+  FOLLY_DEPRECATED("use Try(exception_wrapper)")
+  explicit Try(std::exception_ptr ep)
+    : contains_(Contains::EXCEPTION) {
+    try {
+      std::rethrow_exception(ep);
+    } catch (const std::exception& e) {
+      e_ = folly::make_unique<exception_wrapper>(std::current_exception(), e);
+    } catch (...) {
+      e_ = folly::make_unique<exception_wrapper>(std::current_exception());
+    }
+  }
+
+  // Move constructor
+  Try(Try<T>&& t) noexcept;
+  // Move assigner
+  Try& operator=(Try<T>&& t) noexcept;
+
+  // Copy constructor
+  Try(const Try& t);
+  // Copy assigner
+  Try& operator=(const Try& t);
+
+  ~Try();
+
+  /*
+   * Get a mutable reference to the contained value. If the Try contains an
+   * exception it will be rethrown.
+   *
+   * @returns mutable reference to the contained value
+   */
+  T& value()&;
+  /*
+   * Get a rvalue reference to the contained value. If the Try contains an
+   * exception it will be rethrown.
+   *
+   * @returns rvalue reference to the contained value
+   */
+  T&& value()&&;
+  /*
+   * Get a const reference to the contained value. If the Try contains an
+   * exception it will be rethrown.
+   *
+   * @returns const reference to the contained value
+   */
+  const T& value() const&;
+
+  /*
+   * If the Try contains an exception, rethrow it. Otherwise do nothing.
+   */
+  void throwIfFailed() const;
+
+  /*
+   * Const dereference operator. If the Try contains an exception it will be
+   * rethrown.
+   *
+   * @returns const reference to the contained value
+   */
+  const T& operator*() const { return value(); }
+  /*
+   * Dereference operator. If the Try contains an exception it will be rethrown.
+   *
+   * @returns mutable reference to the contained value
+   */
+  T& operator*() { return value(); }
+
+  /*
+   * Const arrow operator. If the Try contains an exception it will be
+   * rethrown.
+   *
+   * @returns const reference to the contained value
+   */
+  const T* operator->() const { return &value(); }
+  /*
+   * Arrow operator. If the Try contains an exception it will be rethrown.
+   *
+   * @returns mutable reference to the contained value
+   */
+  T* operator->() { return &value(); }
+
+  /*
+   * @returns True if the Try contains a value, false otherwise
+   */
+  bool hasValue() const { return contains_ == Contains::VALUE; }
+  /*
+   * @returns True if the Try contains an exception, false otherwise
+   */
+  bool hasException() const { return contains_ == Contains::EXCEPTION; }
+
+  /*
+   * @returns True if the Try contains an exception of type Ex, false otherwise
+   */
+  template <class Ex>
+  bool hasException() const {
+    return hasException() && e_->is_compatible_with<Ex>();
+  }
+
+  exception_wrapper& exception() {
+    if (UNLIKELY(!hasException())) {
+      throw TryException("exception(): Try does not contain an exception");
+    }
+    return *e_;
+  }
+
+  const exception_wrapper& exception() const {
+    if (UNLIKELY(!hasException())) {
+      throw TryException("exception(): Try does not contain an exception");
+    }
+    return *e_;
+  }
+
+  /*
+   * If the Try contains an exception and it is of type Ex, execute func(Ex)
+   *
+   * @param func a function that takes a single parameter of type const Ex&
+   *
+   * @returns True if the Try held an Ex and func was executed, false otherwise
+   */
+  template <class Ex, class F>
+  bool withException(F func) const {
+    if (!hasException()) {
+      return false;
+    }
+    return e_->with_exception(std::move(func));
+  }
+
+  template <bool isTry, typename R>
+  typename std::enable_if<isTry, R>::type get() {
+    return std::forward<R>(*this);
+  }
+
+  template <bool isTry, typename R>
+  typename std::enable_if<!isTry, R>::type get() {
+    return std::forward<R>(value());
+  }
+
+ private:
+  Contains contains_;
+  union {
+    T value_;
+    std::unique_ptr<exception_wrapper> e_;
+  };
+};
+
+/*
+ * Specialization of Try for void value type. Encapsulates either success or an
+ * exception.
+ */
+template <>
+class Try<void> {
+ public:
+  /*
+   * The value type for the Try
+   */
+  typedef void element_type;
+
+  // Construct a Try holding a successful and void result
+  Try() : hasValue_(true) {}
+
+  /*
+   * Construct a Try with an exception_wrapper
+   *
+   * @param e The exception_wrapper
+   */
+  explicit Try(exception_wrapper e)
+    : hasValue_(false),
+      e_(folly::make_unique<exception_wrapper>(std::move(e))) {}
+
+  /*
+   * DEPRECATED
+   * Construct a Try with an exception_pointer
+   *
+   * @param ep The exception_pointer. Will be rethrown.
+   */
+  FOLLY_DEPRECATED("use Try(exception_wrapper)")
+  explicit Try(std::exception_ptr ep) : hasValue_(false) {
+    try {
+      std::rethrow_exception(ep);
+    } catch (const std::exception& e) {
+      e_ = folly::make_unique<exception_wrapper>(std::current_exception(), e);
+    } catch (...) {
+      e_ = folly::make_unique<exception_wrapper>(std::current_exception());
+    }
+  }
+
+  // Copy assigner
+  Try& operator=(const Try<void>& t) {
+    hasValue_ = t.hasValue_;
+    if (t.e_) {
+      e_ = folly::make_unique<exception_wrapper>(*t.e_);
+    }
+    return *this;
+  }
+  // Copy constructor
+  Try(const Try<void>& t) {
+    *this = t;
+  }
+
+  // If the Try contains an exception, throws it
+  void value() const { throwIfFailed(); }
+  // Dereference operator. If the Try contains an exception, throws it
+  void operator*() const { return value(); }
+
+  // If the Try contains an exception, throws it
+  inline void throwIfFailed() const;
+
+  // @returns False if the Try contains an exception, true otherwise
+  bool hasValue() const { return hasValue_; }
+  // @returns True if the Try contains an exception, false otherwise
+  bool hasException() const { return !hasValue_; }
+
+  // @returns True if the Try contains an exception of type Ex, false otherwise
+  template <class Ex>
+  bool hasException() const {
+    return hasException() && e_->is_compatible_with<Ex>();
+  }
+
+  /*
+   * @throws TryException if the Try doesn't contain an exception
+   *
+   * @returns mutable reference to the exception contained by this Try
+   */
+  exception_wrapper& exception() {
+    if (UNLIKELY(!hasException())) {
+      throw TryException("exception(): Try does not contain an exception");
+    }
+    return *e_;
+  }
+
+  const exception_wrapper& exception() const {
+    if (UNLIKELY(!hasException())) {
+      throw TryException("exception(): Try does not contain an exception");
+    }
+    return *e_;
+  }
+
+  /*
+   * If the Try contains an exception and it is of type Ex, execute func(Ex)
+   *
+   * @param func a function that takes a single parameter of type const Ex&
+   *
+   * @returns True if the Try held an Ex and func was executed, false otherwise
+   */
+  template <class Ex, class F>
+  bool withException(F func) const {
+    if (!hasException()) {
+      return false;
+    }
+    return e_->with_exception(std::move(func));
+  }
+
+  template <bool, typename R>
+  R get() {
+    return std::forward<R>(*this);
+  }
+
+ private:
+  bool hasValue_;
+  std::unique_ptr<exception_wrapper> e_{nullptr};
+};
+
+/*
+ * Extracts value from try and returns it. Throws if try contained an exception.
+ *
+ * @param t Try to extract value from
+ *
+ * @returns value contained in t
+ */
+template <typename T>
+T moveFromTry(Try<T>& t);
+
+/*
+ * Throws if try contained an exception.
+ *
+ * @param t Try to move from
+ */
+void moveFromTry(Try<void>& t);
+
+/*
+ * @param f a function to execute and capture the result of (value or exception)
+ *
+ * @returns Try holding the result of f
+ */
+template <typename F>
+typename std::enable_if<
+  !std::is_same<typename std::result_of<F()>::type, void>::value,
+  Try<typename std::result_of<F()>::type>>::type
+makeTryWith(F&& f);
+
+/*
+ * Specialization of makeTryWith for void return
+ *
+ * @param f a function to execute and capture the result of
+ *
+ * @returns Try<void> holding the result of f
+ */
+template <typename F>
+typename std::enable_if<
+  std::is_same<typename std::result_of<F()>::type, void>::value,
+  Try<void>>::type
+makeTryWith(F&& f);
+
+} // folly
+
+#include <folly/Try-inl.h>
index 9e65fcce4478706bf1dde2f06eda71e6a0ebe88e..63785eaf15752f196454a35ba31e8ffe8a2b51d6 100644 (file)
@@ -21,7 +21,7 @@
 #include <folly/Optional.h>
 #include <folly/fibers/FiberManager.h>
 #include <folly/fibers/Promise.h>
 #include <folly/Optional.h>
 #include <folly/fibers/FiberManager.h>
 #include <folly/fibers/Promise.h>
-#include <folly/futures/Try.h>
+#include <folly/Try.h>
 
 namespace folly {
 namespace fibers {
 
 namespace folly {
 namespace fibers {
index 6b4e94a1f055afb26eb494a48d450fe64da99789..0e14525dec1b9c0b50e8d0634b6703dbbf31e708 100644 (file)
@@ -30,7 +30,7 @@
 #include <folly/fibers/LoopController.h>
 #include <folly/fibers/Promise.h>
 #include <folly/futures/Promise.h>
 #include <folly/fibers/LoopController.h>
 #include <folly/fibers/Promise.h>
 #include <folly/futures/Promise.h>
-#include <folly/futures/Try.h>
+#include <folly/Try.h>
 
 namespace folly {
 namespace fibers {
 
 namespace folly {
 namespace fibers {
index a617dd6bce5674796cdc0f5c661d12468a468290..a2474b62b1e4398b5f1ca2e2eba5e2ed0a019697 100644 (file)
@@ -28,7 +28,7 @@
 #include <folly/Executor.h>
 #include <folly/IntrusiveList.h>
 #include <folly/Likely.h>
 #include <folly/Executor.h>
 #include <folly/IntrusiveList.h>
 #include <folly/Likely.h>
-#include <folly/futures/Try.h>
+#include <folly/Try.h>
 #include <folly/io/async/Request.h>
 
 #include <folly/experimental/ExecutionObserver.h>
 #include <folly/io/async/Request.h>
 
 #include <folly/experimental/ExecutionObserver.h>
index 807898ef4046be18eb0aefe914b2b38796ae054c..fde863dafdc9baa3f3e021bd297d4143aee8757e 100644 (file)
@@ -16,7 +16,7 @@
 #pragma once
 
 #include <folly/fibers/traits.h>
 #pragma once
 
 #include <folly/fibers/traits.h>
-#include <folly/futures/Try.h>
+#include <folly/Try.h>
 
 namespace folly {
 namespace fibers {
 
 namespace folly {
 namespace fibers {
index 990f2990b581904525ec82dcb1e535ece905d427..c3249fdef836090ef6cb9e0e27ff9d5c0f8b842e 100644 (file)
@@ -27,7 +27,7 @@
 #include <folly/Portability.h>
 #include <folly/futures/DrivableExecutor.h>
 #include <folly/futures/Promise.h>
 #include <folly/Portability.h>
 #include <folly/futures/DrivableExecutor.h>
 #include <folly/futures/Promise.h>
-#include <folly/futures/Try.h>
+#include <folly/Try.h>
 #include <folly/futures/FutureException.h>
 #include <folly/futures/detail/Types.h>
 
 #include <folly/futures/FutureException.h>
 #include <folly/futures/detail/Types.h>
 
index 379ad5d6fdc2b5c273a1cfeb5ff44110936370d6..b18f59b2808d59f5b365c6f890c5f87e3489ee43 100644 (file)
@@ -17,7 +17,7 @@
 #pragma once
 
 #include <folly/Portability.h>
 #pragma once
 
 #include <folly/Portability.h>
-#include <folly/futures/Try.h>
+#include <folly/Try.h>
 #include <functional>
 
 namespace folly {
 #include <functional>
 
 namespace folly {
index 1a9e07fd07e06f6e9c27cfbb8afe918ef9d920c2..1af0945dc32df18177bd86afab6948bbfad8b024 100644 (file)
@@ -259,7 +259,7 @@ Although inspired by the C++11 std::future interface, it is not a drop-in replac
 
 <p>That <tt>then()</tt> method on futures is the real bread and butter of Futures code. It allows you to provide a callback which will be executed when that <tt>Future</tt> is complete. Note that while we fulfill the promise after setting the callback here, those operations could be swapped. Setting a callback on an already completed future executes the callback immediately.</p>
 
 
 <p>That <tt>then()</tt> method on futures is the real bread and butter of Futures code. It allows you to provide a callback which will be executed when that <tt>Future</tt> is complete. Note that while we fulfill the promise after setting the callback here, those operations could be swapped. Setting a callback on an already completed future executes the callback immediately.</p>
 
-<p>In this case, the callback takes a value directly. If the Future contained an exception, the callback will be passed over and the exception will be propagated to the resultant Future - more on that in a second. Your callback may also take a <a href="https://github.com/facebook/folly/blob/master/folly/futures/Try.h" target="_blank">Try</a>, which encapsulates either an exception or a value of its templated type.</p>
+<p>In this case, the callback takes a value directly. If the Future contained an exception, the callback will be passed over and the exception will be propagated to the resultant Future - more on that in a second. Your callback may also take a <a href="https://github.com/facebook/folly/blob/master/folly/Try.h" target="_blank">Try</a>, which encapsulates either an exception or a value of its templated type.</p>
 
 <div class="remarkup-code-block" data-code-lang="cpp"><pre class="remarkup-code"><span class=""></span><span class="n">f</span><span class="p">.</span><span class="n">then</span><span class="p">(</span><span class="p">[</span><span class="p">]</span><span class="p">(</span><span class="n">Try</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span><span class=""> </span><span class="k">const</span><span class="o">&amp;</span><span class=""> </span><span class="n">t</span><span class="p">)</span><span class="p">&#123;</span><span class="">
 </span><span class="">  </span><span class="n">cout</span><span class=""> </span><span class="o">&lt;</span><span class="o">&lt;</span><span class=""> </span><span class="n">t</span><span class="p">.</span><span class="n">value</span><span class="p">(</span><span class="p">)</span><span class="p">;</span><span class="">
 
 <div class="remarkup-code-block" data-code-lang="cpp"><pre class="remarkup-code"><span class=""></span><span class="n">f</span><span class="p">.</span><span class="n">then</span><span class="p">(</span><span class="p">[</span><span class="p">]</span><span class="p">(</span><span class="n">Try</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span><span class=""> </span><span class="k">const</span><span class="o">&amp;</span><span class=""> </span><span class="n">t</span><span class="p">)</span><span class="p">&#123;</span><span class="">
 </span><span class="">  </span><span class="n">cout</span><span class=""> </span><span class="o">&lt;</span><span class="o">&lt;</span><span class=""> </span><span class="n">t</span><span class="p">.</span><span class="n">value</span><span class="p">(</span><span class="p">)</span><span class="p">;</span><span class="">
diff --git a/folly/futures/Try-inl.h b/folly/futures/Try-inl.h
deleted file mode 100644 (file)
index ba988e3..0000000
+++ /dev/null
@@ -1,176 +0,0 @@
-/*
- * Copyright 2016 Facebook, Inc.
- *
- * 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 <stdexcept>
-
-namespace folly {
-
-template <class T>
-Try<T>::Try(Try<T>&& t) noexcept : contains_(t.contains_) {
-  if (contains_ == Contains::VALUE) {
-    new (&value_)T(std::move(t.value_));
-  } else if (contains_ == Contains::EXCEPTION) {
-    new (&e_)std::unique_ptr<exception_wrapper>(std::move(t.e_));
-  }
-}
-
-template <class T>
-template <class T2>
-Try<T>::Try(typename std::enable_if<std::is_same<Unit, T2>::value,
-                                    Try<void> const&>::type t)
-    : contains_(Contains::NOTHING) {
-  if (t.hasValue()) {
-    contains_ = Contains::VALUE;
-    new (&value_) T();
-  } else if (t.hasException()) {
-    contains_ = Contains::EXCEPTION;
-    new (&e_) std::unique_ptr<exception_wrapper>(
-        folly::make_unique<exception_wrapper>(t.exception()));
-  }
-}
-
-template <class T>
-Try<T>& Try<T>::operator=(Try<T>&& t) noexcept {
-  if (this == &t) {
-    return *this;
-  }
-
-  this->~Try();
-  contains_ = t.contains_;
-  if (contains_ == Contains::VALUE) {
-    new (&value_)T(std::move(t.value_));
-  } else if (contains_ == Contains::EXCEPTION) {
-    new (&e_)std::unique_ptr<exception_wrapper>(std::move(t.e_));
-  }
-  return *this;
-}
-
-template <class T>
-Try<T>::Try(const Try<T>& t) {
-  static_assert(
-      std::is_copy_constructible<T>::value,
-      "T must be copyable for Try<T> to be copyable");
-  contains_ = t.contains_;
-  if (contains_ == Contains::VALUE) {
-    new (&value_)T(t.value_);
-  } else if (contains_ == Contains::EXCEPTION) {
-    new (&e_)std::unique_ptr<exception_wrapper>();
-    e_ = folly::make_unique<exception_wrapper>(*(t.e_));
-  }
-}
-
-template <class T>
-Try<T>& Try<T>::operator=(const Try<T>& t) {
-  static_assert(
-      std::is_copy_constructible<T>::value,
-      "T must be copyable for Try<T> to be copyable");
-  this->~Try();
-  contains_ = t.contains_;
-  if (contains_ == Contains::VALUE) {
-    new (&value_)T(t.value_);
-  } else if (contains_ == Contains::EXCEPTION) {
-    new (&e_)std::unique_ptr<exception_wrapper>();
-    e_ = folly::make_unique<exception_wrapper>(*(t.e_));
-  }
-  return *this;
-}
-
-template <class T>
-Try<T>::~Try() {
-  if (LIKELY(contains_ == Contains::VALUE)) {
-    value_.~T();
-  } else if (UNLIKELY(contains_ == Contains::EXCEPTION)) {
-    e_.~unique_ptr<exception_wrapper>();
-  }
-}
-
-template <class T>
-T& Try<T>::value() & {
-  throwIfFailed();
-  return value_;
-}
-
-template <class T>
-T&& Try<T>::value() && {
-  throwIfFailed();
-  return std::move(value_);
-}
-
-template <class T>
-const T& Try<T>::value() const & {
-  throwIfFailed();
-  return value_;
-}
-
-template <class T>
-void Try<T>::throwIfFailed() const {
-  if (contains_ != Contains::VALUE) {
-    if (contains_ == Contains::EXCEPTION) {
-      e_->throwException();
-    } else {
-      throw UsingUninitializedTry();
-    }
-  }
-}
-
-void Try<void>::throwIfFailed() const {
-  if (!hasValue_) {
-    e_->throwException();
-  }
-}
-
-template <typename T>
-inline T moveFromTry(Try<T>& t) {
-  return std::move(t.value());
-}
-
-inline void moveFromTry(Try<void>& t) {
-  return t.value();
-}
-
-template <typename F>
-typename std::enable_if<
-  !std::is_same<typename std::result_of<F()>::type, void>::value,
-  Try<typename std::result_of<F()>::type>>::type
-makeTryWith(F&& f) {
-  typedef typename std::result_of<F()>::type ResultType;
-  try {
-    return Try<ResultType>(f());
-  } catch (std::exception& e) {
-    return Try<ResultType>(exception_wrapper(std::current_exception(), e));
-  } catch (...) {
-    return Try<ResultType>(exception_wrapper(std::current_exception()));
-  }
-}
-
-template <typename F>
-typename std::enable_if<
-  std::is_same<typename std::result_of<F()>::type, void>::value,
-  Try<void>>::type
-makeTryWith(F&& f) {
-  try {
-    f();
-    return Try<void>();
-  } catch (std::exception& e) {
-    return Try<void>(exception_wrapper(std::current_exception(), e));
-  } catch (...) {
-    return Try<void>(exception_wrapper(std::current_exception()));
-  }
-}
-
-} // folly
diff --git a/folly/futures/Try.h b/folly/futures/Try.h
deleted file mode 100644 (file)
index ab37a59..0000000
+++ /dev/null
@@ -1,423 +0,0 @@
-/*
- * Copyright 2016 Facebook, Inc.
- *
- * 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 <type_traits>
-#include <exception>
-#include <algorithm>
-#include <folly/ExceptionWrapper.h>
-#include <folly/Likely.h>
-#include <folly/Memory.h>
-#include <folly/Portability.h>
-#include <folly/Unit.h>
-
-namespace folly {
-
-class TryException : public std::exception {
- public:
-  explicit TryException(std::string message_arg) noexcept
-      : message(std::move(message_arg)) {}
-
-  const char* what() const noexcept override {
-    return message.c_str();
-  }
-
-  bool operator==(const TryException& other) const noexcept {
-    return other.message == this->message;
-  }
-
-  bool operator!=(const TryException& other) const noexcept {
-    return !(*this == other);
-  }
-
- protected:
-  std::string message;
-};
-
-class UsingUninitializedTry : public TryException {
- public:
-  UsingUninitializedTry() noexcept : TryException("Using unitialized try") {}
-};
-
-/*
- * Try<T> is a wrapper that contains either an instance of T, an exception, or
- * nothing. Exceptions are stored as exception_wrappers so that the user can
- * minimize rethrows if so desired.
- *
- * To represent success or a captured exception, use Try<Unit>.
- */
-template <class T>
-class Try {
-  static_assert(!std::is_reference<T>::value,
-                "Try may not be used with reference types");
-
-  enum class Contains {
-    VALUE,
-    EXCEPTION,
-    NOTHING,
-  };
-
- public:
-  /*
-   * The value type for the Try
-   */
-  typedef T element_type;
-
-  /*
-   * Construct an empty Try
-   */
-  Try() : contains_(Contains::NOTHING) {}
-
-  /*
-   * Construct a Try with a value by copy
-   *
-   * @param v The value to copy in
-   */
-  explicit Try(const T& v) : contains_(Contains::VALUE), value_(v) {}
-
-  /*
-   * Construct a Try with a value by move
-   *
-   * @param v The value to move in
-   */
-  explicit Try(T&& v) : contains_(Contains::VALUE), value_(std::move(v)) {}
-
-  /// Implicit conversion from Try<void> to Try<Unit>
-  template <class T2 = T>
-  /* implicit */
-  Try(typename std::enable_if<std::is_same<Unit, T2>::value,
-                              Try<void> const&>::type t);
-
-  /*
-   * Construct a Try with an exception_wrapper
-   *
-   * @param e The exception_wrapper
-   */
-  explicit Try(exception_wrapper e)
-    : contains_(Contains::EXCEPTION),
-      e_(folly::make_unique<exception_wrapper>(std::move(e))) {}
-
-  /*
-   * DEPRECATED
-   * Construct a Try with an exception_pointer
-   *
-   * @param ep The exception_pointer. Will be rethrown.
-   */
-  FOLLY_DEPRECATED("use Try(exception_wrapper)")
-  explicit Try(std::exception_ptr ep)
-    : contains_(Contains::EXCEPTION) {
-    try {
-      std::rethrow_exception(ep);
-    } catch (const std::exception& e) {
-      e_ = folly::make_unique<exception_wrapper>(std::current_exception(), e);
-    } catch (...) {
-      e_ = folly::make_unique<exception_wrapper>(std::current_exception());
-    }
-  }
-
-  // Move constructor
-  Try(Try<T>&& t) noexcept;
-  // Move assigner
-  Try& operator=(Try<T>&& t) noexcept;
-
-  // Copy constructor
-  Try(const Try& t);
-  // Copy assigner
-  Try& operator=(const Try& t);
-
-  ~Try();
-
-  /*
-   * Get a mutable reference to the contained value. If the Try contains an
-   * exception it will be rethrown.
-   *
-   * @returns mutable reference to the contained value
-   */
-  T& value()&;
-  /*
-   * Get a rvalue reference to the contained value. If the Try contains an
-   * exception it will be rethrown.
-   *
-   * @returns rvalue reference to the contained value
-   */
-  T&& value()&&;
-  /*
-   * Get a const reference to the contained value. If the Try contains an
-   * exception it will be rethrown.
-   *
-   * @returns const reference to the contained value
-   */
-  const T& value() const&;
-
-  /*
-   * If the Try contains an exception, rethrow it. Otherwise do nothing.
-   */
-  void throwIfFailed() const;
-
-  /*
-   * Const dereference operator. If the Try contains an exception it will be
-   * rethrown.
-   *
-   * @returns const reference to the contained value
-   */
-  const T& operator*() const { return value(); }
-  /*
-   * Dereference operator. If the Try contains an exception it will be rethrown.
-   *
-   * @returns mutable reference to the contained value
-   */
-  T& operator*() { return value(); }
-
-  /*
-   * Const arrow operator. If the Try contains an exception it will be
-   * rethrown.
-   *
-   * @returns const reference to the contained value
-   */
-  const T* operator->() const { return &value(); }
-  /*
-   * Arrow operator. If the Try contains an exception it will be rethrown.
-   *
-   * @returns mutable reference to the contained value
-   */
-  T* operator->() { return &value(); }
-
-  /*
-   * @returns True if the Try contains a value, false otherwise
-   */
-  bool hasValue() const { return contains_ == Contains::VALUE; }
-  /*
-   * @returns True if the Try contains an exception, false otherwise
-   */
-  bool hasException() const { return contains_ == Contains::EXCEPTION; }
-
-  /*
-   * @returns True if the Try contains an exception of type Ex, false otherwise
-   */
-  template <class Ex>
-  bool hasException() const {
-    return hasException() && e_->is_compatible_with<Ex>();
-  }
-
-  exception_wrapper& exception() {
-    if (UNLIKELY(!hasException())) {
-      throw TryException("exception(): Try does not contain an exception");
-    }
-    return *e_;
-  }
-
-  const exception_wrapper& exception() const {
-    if (UNLIKELY(!hasException())) {
-      throw TryException("exception(): Try does not contain an exception");
-    }
-    return *e_;
-  }
-
-  /*
-   * If the Try contains an exception and it is of type Ex, execute func(Ex)
-   *
-   * @param func a function that takes a single parameter of type const Ex&
-   *
-   * @returns True if the Try held an Ex and func was executed, false otherwise
-   */
-  template <class Ex, class F>
-  bool withException(F func) const {
-    if (!hasException()) {
-      return false;
-    }
-    return e_->with_exception(std::move(func));
-  }
-
-  template <bool isTry, typename R>
-  typename std::enable_if<isTry, R>::type get() {
-    return std::forward<R>(*this);
-  }
-
-  template <bool isTry, typename R>
-  typename std::enable_if<!isTry, R>::type get() {
-    return std::forward<R>(value());
-  }
-
- private:
-  Contains contains_;
-  union {
-    T value_;
-    std::unique_ptr<exception_wrapper> e_;
-  };
-};
-
-/*
- * Specialization of Try for void value type. Encapsulates either success or an
- * exception.
- */
-template <>
-class Try<void> {
- public:
-  /*
-   * The value type for the Try
-   */
-  typedef void element_type;
-
-  // Construct a Try holding a successful and void result
-  Try() : hasValue_(true) {}
-
-  /*
-   * Construct a Try with an exception_wrapper
-   *
-   * @param e The exception_wrapper
-   */
-  explicit Try(exception_wrapper e)
-    : hasValue_(false),
-      e_(folly::make_unique<exception_wrapper>(std::move(e))) {}
-
-  /*
-   * DEPRECATED
-   * Construct a Try with an exception_pointer
-   *
-   * @param ep The exception_pointer. Will be rethrown.
-   */
-  FOLLY_DEPRECATED("use Try(exception_wrapper)")
-  explicit Try(std::exception_ptr ep) : hasValue_(false) {
-    try {
-      std::rethrow_exception(ep);
-    } catch (const std::exception& e) {
-      e_ = folly::make_unique<exception_wrapper>(std::current_exception(), e);
-    } catch (...) {
-      e_ = folly::make_unique<exception_wrapper>(std::current_exception());
-    }
-  }
-
-  // Copy assigner
-  Try& operator=(const Try<void>& t) {
-    hasValue_ = t.hasValue_;
-    if (t.e_) {
-      e_ = folly::make_unique<exception_wrapper>(*t.e_);
-    }
-    return *this;
-  }
-  // Copy constructor
-  Try(const Try<void>& t) {
-    *this = t;
-  }
-
-  // If the Try contains an exception, throws it
-  void value() const { throwIfFailed(); }
-  // Dereference operator. If the Try contains an exception, throws it
-  void operator*() const { return value(); }
-
-  // If the Try contains an exception, throws it
-  inline void throwIfFailed() const;
-
-  // @returns False if the Try contains an exception, true otherwise
-  bool hasValue() const { return hasValue_; }
-  // @returns True if the Try contains an exception, false otherwise
-  bool hasException() const { return !hasValue_; }
-
-  // @returns True if the Try contains an exception of type Ex, false otherwise
-  template <class Ex>
-  bool hasException() const {
-    return hasException() && e_->is_compatible_with<Ex>();
-  }
-
-  /*
-   * @throws TryException if the Try doesn't contain an exception
-   *
-   * @returns mutable reference to the exception contained by this Try
-   */
-  exception_wrapper& exception() {
-    if (UNLIKELY(!hasException())) {
-      throw TryException("exception(): Try does not contain an exception");
-    }
-    return *e_;
-  }
-
-  const exception_wrapper& exception() const {
-    if (UNLIKELY(!hasException())) {
-      throw TryException("exception(): Try does not contain an exception");
-    }
-    return *e_;
-  }
-
-  /*
-   * If the Try contains an exception and it is of type Ex, execute func(Ex)
-   *
-   * @param func a function that takes a single parameter of type const Ex&
-   *
-   * @returns True if the Try held an Ex and func was executed, false otherwise
-   */
-  template <class Ex, class F>
-  bool withException(F func) const {
-    if (!hasException()) {
-      return false;
-    }
-    return e_->with_exception(std::move(func));
-  }
-
-  template <bool, typename R>
-  R get() {
-    return std::forward<R>(*this);
-  }
-
- private:
-  bool hasValue_;
-  std::unique_ptr<exception_wrapper> e_{nullptr};
-};
-
-/*
- * Extracts value from try and returns it. Throws if try contained an exception.
- *
- * @param t Try to extract value from
- *
- * @returns value contained in t
- */
-template <typename T>
-T moveFromTry(Try<T>& t);
-
-/*
- * Throws if try contained an exception.
- *
- * @param t Try to move from
- */
-void moveFromTry(Try<void>& t);
-
-/*
- * @param f a function to execute and capture the result of (value or exception)
- *
- * @returns Try holding the result of f
- */
-template <typename F>
-typename std::enable_if<
-  !std::is_same<typename std::result_of<F()>::type, void>::value,
-  Try<typename std::result_of<F()>::type>>::type
-makeTryWith(F&& f);
-
-/*
- * Specialization of makeTryWith for void return
- *
- * @param f a function to execute and capture the result of
- *
- * @returns Try<void> holding the result of f
- */
-template <typename F>
-typename std::enable_if<
-  std::is_same<typename std::result_of<F()>::type, void>::value,
-  Try<void>>::type
-makeTryWith(F&& f);
-
-} // folly
-
-#include <folly/futures/Try-inl.h>
index d3dba861613506f7727f627477037c9125cfa1f9..a6ac6109a643da5549144b9986e838267a26e4c6 100644 (file)
@@ -27,7 +27,7 @@
 #include <folly/Optional.h>
 #include <folly/futures/Future.h>
 #include <folly/futures/Promise.h>
 #include <folly/Optional.h>
 #include <folly/futures/Future.h>
 #include <folly/futures/Promise.h>
-#include <folly/futures/Try.h>
+#include <folly/Try.h>
 #include <folly/futures/detail/FSM.h>
 
 #include <folly/io/async/Request.h>
 #include <folly/futures/detail/FSM.h>
 
 #include <folly/io/async/Request.h>
index cbee3d04643348b99274c4a97b4eed73c54f3800..ae2e5dedc02b7f52086d122928c81075e6325633 100644 (file)
@@ -18,7 +18,7 @@
 
 // amazing what things can go wrong if you include things in an unexpected
 // order.
 
 // amazing what things can go wrong if you include things in an unexpected
 // order.
-#include <folly/futures/Try.h>
+#include <folly/Try.h>
 #include <folly/futures/Promise.h>
 #include <folly/futures/Future.h>
 
 #include <folly/futures/Promise.h>
 #include <folly/futures/Future.h>
 
diff --git a/folly/futures/test/TryTest.cpp b/folly/futures/test/TryTest.cpp
deleted file mode 100644 (file)
index 899db52..0000000
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Copyright 2016 Facebook, Inc.
- *
- * 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.
- */
-
-#include <gtest/gtest.h>
-
-#include <folly/Memory.h>
-#include <folly/futures/Try.h>
-
-using namespace folly;
-
-TEST(Try, basic) {
-  class A {
-   public:
-    A(int x) : x_(x) {}
-
-    int x() const {
-      return x_;
-    }
-   private:
-    int x_;
-  };
-
-  A a(5);
-  Try<A> t_a(std::move(a));
-
-  Try<Unit> t_void;
-
-  EXPECT_EQ(5, t_a.value().x());
-}
-
-// Make sure we can copy Trys for copyable types
-TEST(Try, copy) {
-  Try<int> t;
-  auto t2 = t;
-}
-
-// But don't choke on move-only types
-TEST(Try, moveOnly) {
-  Try<std::unique_ptr<int>> t;
-  std::vector<Try<std::unique_ptr<int>>> v;
-  v.reserve(10);
-}
-
-TEST(Try, makeTryWith) {
-  auto func = []() {
-    return folly::make_unique<int>(1);
-  };
-
-  auto result = makeTryWith(func);
-  EXPECT_TRUE(result.hasValue());
-  EXPECT_EQ(*result.value(), 1);
-}
-
-TEST(Try, makeTryWithThrow) {
-  auto func = []() {
-    throw std::runtime_error("Runtime");
-    return folly::make_unique<int>(1);
-  };
-
-  auto result = makeTryWith(func);
-  EXPECT_TRUE(result.hasException<std::runtime_error>());
-}
-
-TEST(Try, makeTryWithVoid) {
-  auto func = []() {
-    return;
-  };
-
-  auto result = makeTryWith(func);
-  EXPECT_TRUE(result.hasValue());
-}
-
-TEST(Try, makeTryWithVoidThrow) {
-  auto func = []() {
-    throw std::runtime_error("Runtime");
-    return;
-  };
-
-  auto result = makeTryWith(func);
-  EXPECT_TRUE(result.hasException<std::runtime_error>());
-}
index 9932fe6150281b2a3c80286c8329d3ede03f4081..4d000a9a7da16d13f6aefc5120971618badc3d9d 100644 (file)
@@ -215,6 +215,10 @@ indestructible_test_SOURCES = IndestructibleTest.cpp
 indestructible_test_LDADD = libfollytestmain.la
 TESTS += indestructible_test
 
 indestructible_test_LDADD = libfollytestmain.la
 TESTS += indestructible_test
 
+try_test_SOURCES = TryTest.cpp
+try_test_LDADD = libfollytestmain.la
+TESTS += try_test
+
 unit_test_SOURCES = UnitTest.cpp
 unit_test_LDADD = libfollytestmain.la
 TESTS += unit_test
 unit_test_SOURCES = UnitTest.cpp
 unit_test_LDADD = libfollytestmain.la
 TESTS += unit_test
@@ -244,7 +248,6 @@ futures_test_SOURCES = \
     ../futures/test/ThenTest.cpp \
     ../futures/test/TimekeeperTest.cpp \
     ../futures/test/TimesTest.cpp \
     ../futures/test/ThenTest.cpp \
     ../futures/test/TimekeeperTest.cpp \
     ../futures/test/TimesTest.cpp \
-    ../futures/test/TryTest.cpp \
     ../futures/test/UnwrapTest.cpp \
     ../futures/test/ViaTest.cpp \
     ../futures/test/WaitTest.cpp \
     ../futures/test/UnwrapTest.cpp \
     ../futures/test/ViaTest.cpp \
     ../futures/test/WaitTest.cpp \
diff --git a/folly/test/TryTest.cpp b/folly/test/TryTest.cpp
new file mode 100644 (file)
index 0000000..e1f2c4e
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * Copyright 2016 Facebook, Inc.
+ *
+ * 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.
+ */
+
+#include <gtest/gtest.h>
+
+#include <folly/Memory.h>
+#include <folly/Try.h>
+
+using namespace folly;
+
+TEST(Try, basic) {
+  class A {
+   public:
+    A(int x) : x_(x) {}
+
+    int x() const {
+      return x_;
+    }
+   private:
+    int x_;
+  };
+
+  A a(5);
+  Try<A> t_a(std::move(a));
+
+  Try<Unit> t_void;
+
+  EXPECT_EQ(5, t_a.value().x());
+}
+
+// Make sure we can copy Trys for copyable types
+TEST(Try, copy) {
+  Try<int> t;
+  auto t2 = t;
+}
+
+// But don't choke on move-only types
+TEST(Try, moveOnly) {
+  Try<std::unique_ptr<int>> t;
+  std::vector<Try<std::unique_ptr<int>>> v;
+  v.reserve(10);
+}
+
+TEST(Try, makeTryWith) {
+  auto func = []() {
+    return folly::make_unique<int>(1);
+  };
+
+  auto result = makeTryWith(func);
+  EXPECT_TRUE(result.hasValue());
+  EXPECT_EQ(*result.value(), 1);
+}
+
+TEST(Try, makeTryWithThrow) {
+  auto func = []() {
+    throw std::runtime_error("Runtime");
+    return folly::make_unique<int>(1);
+  };
+
+  auto result = makeTryWith(func);
+  EXPECT_TRUE(result.hasException<std::runtime_error>());
+}
+
+TEST(Try, makeTryWithVoid) {
+  auto func = []() {
+    return;
+  };
+
+  auto result = makeTryWith(func);
+  EXPECT_TRUE(result.hasValue());
+}
+
+TEST(Try, makeTryWithVoidThrow) {
+  auto func = []() {
+    throw std::runtime_error("Runtime");
+    return;
+  };
+
+  auto result = makeTryWith(func);
+  EXPECT_TRUE(result.hasException<std::runtime_error>());
+}