(Wangle) Generic void star callback wrapper
authorHannes Roth <hannesr@fb.com>
Thu, 14 Aug 2014 15:52:49 +0000 (08:52 -0700)
committerSara Golemon <sgolemon@fb.com>
Thu, 14 Aug 2014 18:49:04 +0000 (11:49 -0700)
Summary: Less generic than I hoped for. Naming is terrible.

Test Plan:
`fbconfig -r tao/client && fbmake runtests` -- I figured if it compiles
it works. Also did a `--sanitize=address` build just in case.

Reviewed By: hans@fb.com

Subscribers: fugalh, zhuohuang, anca

FB internal diff: D1470483

folly/wangle/OpaqueCallbackShunt.h [new file with mode: 0644]

diff --git a/folly/wangle/OpaqueCallbackShunt.h b/folly/wangle/OpaqueCallbackShunt.h
new file mode 100644 (file)
index 0000000..296cdea
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * 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 "Promise.h"
+
+namespace folly { namespace wangle {
+
+/// These classes help you wrap an existing C style callback function
+/// into a Future/Later.
+///
+///   void legacy_send_async(..., void (*cb)(void*), void*);
+///
+///   Future<T> wrappedSendAsync(T&& obj) {
+///     auto handle = new OpaqueCallbackShunt<T>(obj);
+///     auto future = handle->promise_.getFuture();
+///     legacy_send_async(..., OpaqueCallbackShunt<T>::callback, handle)
+///     return future;
+///   }
+///
+/// If the legacy function doesn't conform to void (*cb)(void*), use a lambda:
+///
+///   auto cb = [](t1*, t2*, void* arg) {
+///     OpaqueCallbackShunt<T>::callback(arg);
+///   };
+///   legacy_send_async(..., cb, handle);
+
+template <typename T>
+class OpaqueCallbackShunt {
+public:
+  explicit OpaqueCallbackShunt(T&& obj)
+    : obj_(std::move(obj)) { }
+  static void callback(void* arg) {
+    std::unique_ptr<OpaqueCallbackShunt<T>> handle(
+      static_cast<OpaqueCallbackShunt<T>*>(arg));
+    handle->promise_.setValue(std::move(handle->obj_));
+  }
+  folly::wangle::Promise<T> promise_;
+private:
+  T obj_;
+};
+
+/// Variant that returns a Later instead of a Future
+///
+///   Later<int> wrappedSendAsyncLater(int i) {
+///     folly::MoveWrapper<int> wrapped(std::move(i));
+///     return Later<int>(
+///       [..., wrapped](std::function<void(int&&)>&& fn) mutable {
+///         auto handle = new OpaqueCallbackLaterShunt<int>(
+///           std::move(*wrapped), std::move(fn));
+///         legacy_send_async(...,
+///          OpaqueCallbackLaterShunt<int>::callback, handle);
+///       });
+///   }
+///
+/// Depending on your compiler's kung-fu knowledge, you might need to assign
+/// the lambda to a std::function<void(std::function<void(int&&)>&&)> temporary
+/// variable before std::moving into it into the later.
+
+template <typename T>
+class OpaqueCallbackLaterShunt {
+public:
+  explicit
+  OpaqueCallbackLaterShunt(T&& obj, std::function<void(T&&)>&& fn)
+   : fn_(std::move(fn)), obj_(std::move(obj)) { }
+  static void callback(void* arg) {
+    std::unique_ptr<OpaqueCallbackLaterShunt<T>> handle(
+      static_cast<OpaqueCallbackLaterShunt<T>*>(arg));
+    handle->fn_(std::move(handle->obj_));
+  }
+private:
+  std::function<void(T&&)> fn_;
+  T obj_;
+};
+
+}} // folly::wangle