--- /dev/null
+// This file is @generated by thens.rb
+
+#include "Thens.h"
+
+TEST(Future, thenVariants) {
+ SomeClass anObject;
+ Executor* anExecutor;
+
+ {Future<B> f = someFuture<A>().then(aFunction<Future<B>, Try<A>&&>);}
+ {Future<B> f = someFuture<A>().then(&SomeClass::aStaticMethod<Future<B>, Try<A>&&>);}
+ {Future<B> f = someFuture<A>().then(&anObject, &SomeClass::aMethod<Future<B>, Try<A>&&>);}
+ {Future<B> f = someFuture<A>().then(aStdFunction<Future<B>, Try<A>&&>());}
+ {Future<B> f = someFuture<A>().then([&](Try<A>&&){return someFuture<B>();});}
+ {Future<B> f = someFuture<A>().then(aFunction<B, Try<A>&&>);}
+ {Future<B> f = someFuture<A>().then(&SomeClass::aStaticMethod<B, Try<A>&&>);}
+ {Future<B> f = someFuture<A>().then(&anObject, &SomeClass::aMethod<B, Try<A>&&>);}
+ {Future<B> f = someFuture<A>().then(aStdFunction<B, Try<A>&&>());}
+ {Future<B> f = someFuture<A>().then([&](Try<A>&&){return B();});}
+}
--- /dev/null
+/*
+ * Copyright 2014 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 <gtest/gtest.h>
+#include <memory>
+#include "folly/wangle/Future.h"
+#include "folly/wangle/Executor.h"
+
+using namespace folly::wangle;
+using namespace std;
+using namespace testing;
+
+typedef unique_ptr<int> A;
+struct B {};
+
+template <class T>
+using EnableIfFuture = typename std::enable_if<isFuture<T>::value>::type;
+
+template <class T>
+using EnableUnlessFuture = typename std::enable_if<!isFuture<T>::value>::type;
+
+template <class T>
+Future<T> someFuture() {
+ return makeFuture(T());
+}
+
+template <class Ret, class... Params, typename = void>
+Ret aFunction(Params...);
+
+template <class Ret, class... Params>
+typename std::enable_if<isFuture<Ret>::value, Ret>::type
+aFunction(Params...) {
+ typedef typename Ret::value_type T;
+ return makeFuture(T());
+}
+
+template <class Ret, class... Params>
+typename std::enable_if<!isFuture<Ret>::value, Ret>::type
+aFunction(Params...) {
+ return Ret();
+}
+
+template <class Ret, class... Params>
+std::function<Ret(Params...)>
+aStdFunction(typename std::enable_if<!isFuture<Ret>::value, bool>::type = false) {
+ return [](Params...) -> Ret { return Ret(); };
+}
+
+template <class Ret, class... Params>
+std::function<Ret(Params...)>
+aStdFunction(typename std::enable_if<isFuture<Ret>::value, bool>::type = true) {
+ typedef typename Ret::value_type T;
+ return [](Params...) -> Future<T> { return makeFuture(T()); };
+}
+
+class SomeClass {
+ B b;
+public:
+ template <class Ret, class... Params>
+ static Ret aStaticMethod(Params...);
+
+ template <class Ret, class... Params>
+ static
+ typename std::enable_if<!isFuture<Ret>::value, Ret>::type
+ aStaticMethod(Params...) {
+ return Ret();
+ }
+
+ template <class Ret, class... Params>
+ static
+ typename std::enable_if<isFuture<Ret>::value, Ret>::type
+ aStaticMethod(Params...) {
+ typedef typename Ret::value_type T;
+ return makeFuture(T());
+ }
+
+ template <class Ret, class... Params>
+ Ret aMethod(Params...);
+
+ template <class Ret, class... Params>
+ typename std::enable_if<!isFuture<Ret>::value, Ret>::type
+ aMethod(Params...) {
+ return Ret();
+ }
+
+ template <class Ret, class... Params>
+ typename std::enable_if<isFuture<Ret>::value, Ret>::type
+ aMethod(Params...) {
+ typedef typename Ret::value_type T;
+ return makeFuture(T());
+ }
+};
--- /dev/null
+#!/usr/bin/env ruby
+
+# An exercise in combinatorics.
+# (ordinary/static function, member function, std::function, lambda)
+# X
+# returns (Future<R>, R)
+# X
+# accepts (Try<T>&&, Try<T> const&, Try<T>, T&&, T const&, T, nothing)
+
+def test(*args)
+ args = args.join(", ")
+ [
+ "{Future<B> f = someFuture<A>().then(#{args});}",
+ #"{Future<B> f = makeFuture(A()).then(#{args}, anExecutor);}",
+ ]
+end
+
+def retval(ret)
+ {
+ "Future<B>" => "someFuture<B>()",
+ "Try<B>" => "Try<B>(B())",
+ "B" => "B()"
+ }[ret]
+end
+
+return_types = [
+ "Future<B>",
+ "B",
+ #"Try<B>",
+]
+param_types = [
+ "Try<A>&&",
+ #"Try<A> const&",
+ #"Try<A>",
+ #"Try<A>&",
+ #"A&&",
+ #"A const&",
+ #"A",
+ #"A&",
+ #"",
+ ]
+
+tests = (
+ return_types.map { |ret|
+ param_types.map { |param|
+ both = "#{ret}, #{param}"
+ [
+ ["aFunction<#{both}>"],
+ ["&SomeClass::aStaticMethod<#{both}>"],
+ # TODO switch these around (std::bind-style)
+ ["&anObject", "&SomeClass::aMethod<#{both}>"],
+ ["aStdFunction<#{both}>()"],
+ ["[&](#{param}){return #{retval(ret)};}"],
+ ]
+ }
+ }.flatten(2) + [
+ #[""],
+ ]
+).map {|a| test(a)}.flatten
+
+print <<EOF
+// This file is #{"@"}generated by thens.rb
+
+#include "Thens.h"
+
+TEST(Future, thenVariants) {
+ SomeClass anObject;
+ Executor* anExecutor;
+
+ #{tests.join("\n ")}
+}
+EOF