From 2a015b5f2e931d5f7e80858a9d69d0a826ed48ba Mon Sep 17 00:00:00 2001 From: Hannes Roth Date: Thu, 14 Aug 2014 08:52:49 -0700 Subject: [PATCH] (Wangle) Generic void star callback wrapper 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 | 90 ++++++++++++++++++++++++++++++ 1 file changed, 90 insertions(+) create mode 100644 folly/wangle/OpaqueCallbackShunt.h diff --git a/folly/wangle/OpaqueCallbackShunt.h b/folly/wangle/OpaqueCallbackShunt.h new file mode 100644 index 00000000..296cdea1 --- /dev/null +++ b/folly/wangle/OpaqueCallbackShunt.h @@ -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 wrappedSendAsync(T&& obj) { +/// auto handle = new OpaqueCallbackShunt(obj); +/// auto future = handle->promise_.getFuture(); +/// legacy_send_async(..., OpaqueCallbackShunt::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::callback(arg); +/// }; +/// legacy_send_async(..., cb, handle); + +template +class OpaqueCallbackShunt { +public: + explicit OpaqueCallbackShunt(T&& obj) + : obj_(std::move(obj)) { } + static void callback(void* arg) { + std::unique_ptr> handle( + static_cast*>(arg)); + handle->promise_.setValue(std::move(handle->obj_)); + } + folly::wangle::Promise promise_; +private: + T obj_; +}; + +/// Variant that returns a Later instead of a Future +/// +/// Later wrappedSendAsyncLater(int i) { +/// folly::MoveWrapper wrapped(std::move(i)); +/// return Later( +/// [..., wrapped](std::function&& fn) mutable { +/// auto handle = new OpaqueCallbackLaterShunt( +/// std::move(*wrapped), std::move(fn)); +/// legacy_send_async(..., +/// OpaqueCallbackLaterShunt::callback, handle); +/// }); +/// } +/// +/// Depending on your compiler's kung-fu knowledge, you might need to assign +/// the lambda to a std::function&&)> temporary +/// variable before std::moving into it into the later. + +template +class OpaqueCallbackLaterShunt { +public: + explicit + OpaqueCallbackLaterShunt(T&& obj, std::function&& fn) + : fn_(std::move(fn)), obj_(std::move(obj)) { } + static void callback(void* arg) { + std::unique_ptr> handle( + static_cast*>(arg)); + handle->fn_(std::move(handle->obj_)); + } +private: + std::function fn_; + T obj_; +}; + +}} // folly::wangle -- 2.34.1