Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(2161)

Unified Diff: content/child/scoped_web_callbacks.h

Issue 1293253002: Connect WebUSB client interface to the devices app (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fix memory leak in WeakBindingSet Created 5 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | content/content_child.gypi » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: content/child/scoped_web_callbacks.h
diff --git a/content/child/scoped_web_callbacks.h b/content/child/scoped_web_callbacks.h
new file mode 100644
index 0000000000000000000000000000000000000000..7f578dda93f41a2eb9d6f7918694241ad5aa4d7d
--- /dev/null
+++ b/content/child/scoped_web_callbacks.h
@@ -0,0 +1,107 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_CHILD_SCOPED_WEB_CALLBACKS_H_
+#define CONTENT_CHILD_SCOPED_WEB_CALLBACKS_H_
+
+#include "base/callback.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/move.h"
+#include "third_party/WebKit/public/platform/WebCallbacks.h"
+
+// A ScopedWebCallbacks is a move-only scoper which helps manage the lifetime of
+// a blink::WebCallbacks object. This is particularly useful when you're
+// simultaneously dealing with the following two conditions:
+//
+// 1. Your WebCallbacks implementation requires either onSuccess or onError to
+// be called before it's destroyed. This is the case with
+// CallbackPromiseAdapter for example, because its underlying
+// ScriptPromiseResolver must be resolved or rejected before destruction.
+//
+// 2. You are passing ownership of the WebCallbacks to code which may
+// silenty drop it. A common way for this to happen is to bind the
+// WebCallbacks as an argument to a base::Callback which gets destroyed
+// before it can run.
+//
+// While it's possible to individually track the lifetime of pending
+// WebCallbacks, this becomes cumbersome when dealing with many different
+// callbacks types. ScopedWebCallbacks provides a generic and relatively
+// lightweight solution to this problem.
+//
+// Example usage:
+//
+// using FooCallbacks = blink::WebCallbacks<const Foo&, const FooError&>;
+//
+// void RespondWithSuccess(ScopedWebCallbacks<FooCallbacks> callbacks) {
+// callbacks.PassCallbacks()->onSuccess(Foo("everything is great"));
+// }
+//
+// void OnCallbacksDropped(scoped_ptr<FooCallbacks> callbacks) {
+// // Ownership of the FooCallbacks is passed to this function if
+// // ScopedWebCallbacks::PassCallbacks isn't called before the
+// // ScopedWebCallbacks is destroyed.
+// callbacks->onError(FooError("everything is terrible"));
+// }
+//
+// // Blink client implementation
+// void FooClientImpl::doMagic(FooCallbacks* callbacks) {
+// auto scoped_callbacks = make_scoped_web_callbacks(
+// callbacks, base::Bind(&OnCallbacksDropped));
+//
+// // Call to some lower-level service which may never run the callback we
+// // give it.
+// foo_service_->DoMagic(base::Bind(&RespondWithSuccess,
+// base::Passed(&scoped_callbacks)));
+// }
+//
+// If the bound RespondWithSuccess callback actually runs, PassCallbacks() will
+// reliquish ownership of the WebCallbacks object to a temporary scoped_ptr
+// which will be destroyed immediately after onSuccess is called.
+//
+// If the bound RespondWithSuccess callback is instead destroyed first,
+// the ScopedWebCallbacks destructor will invoke OnCallbacksDropped, executing
+// our desired default behavior before deleting the WebCallbacks.
+template <typename CallbacksType>
+class ScopedWebCallbacks {
+ MOVE_ONLY_TYPE_FOR_CPP_03(ScopedWebCallbacks, RValue);
+
+ public:
+ using DestructionCallback =
+ base::Callback<void(scoped_ptr<CallbacksType> callbacks)>;
+
+ ScopedWebCallbacks(scoped_ptr<CallbacksType> callbacks,
+ const DestructionCallback& destruction_callback)
+ : callbacks_(callbacks.Pass()),
+ destruction_callback_(destruction_callback) {}
+
+ ~ScopedWebCallbacks() {
+ if (callbacks_)
+ destruction_callback_.Run(callbacks_.Pass());
+ }
+
+ ScopedWebCallbacks(RValue other) { *this = other; }
+
+ ScopedWebCallbacks& operator=(RValue other) {
+ callbacks_ = other.object->callbacks_.Pass();
+ destruction_callback_ = other.object->destruction_callback_;
+ return *this;
+ }
+
+ scoped_ptr<CallbacksType> PassCallbacks() { return callbacks_.Pass(); }
+
+ private:
+ scoped_ptr<CallbacksType> callbacks_;
+ DestructionCallback destruction_callback_;
+};
+
+template <typename CallbacksType>
+ScopedWebCallbacks<CallbacksType> make_scoped_web_callbacks(
+ CallbacksType* callbacks,
+ const typename ScopedWebCallbacks<CallbacksType>::DestructionCallback&
+ destruction_callback) {
+ return ScopedWebCallbacks<CallbacksType>(make_scoped_ptr(callbacks),
+ destruction_callback);
+}
+
+#endif // CONTENT_CHILD_SCOPED_WEB_CALLBACKS_H_
« no previous file with comments | « no previous file | content/content_child.gypi » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698