1 // Copyright (c) 2019 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #ifndef CONTENT_BROWSER_INDEXED_DB_INDEXED_DB_CALLBACK_HELPERS_H_
6 #define CONTENT_BROWSER_INDEXED_DB_INDEXED_DB_CALLBACK_HELPERS_H_
7
8 #include <memory>
9 #include <utility>
10
11 #include "base/logging.h"
12 #include "base/memory/weak_ptr.h"
13 #include "content/browser/indexed_db/indexed_db_transaction.h"
14 #include "third_party/blink/public/mojom/indexeddb/indexeddb.mojom-forward.h"
15 #include "third_party/leveldatabase/env_chromium.h"
16
17 // Since functions in this file use templates, they must be in a header file
18 // and can't be placed in a definition file. Please ensure any including file
19 // is a definition file, itself, and never include this into a header file.
20
21 namespace content {
22 namespace indexed_db_callback_helpers_internal {
23
24 template <typename T>
InvokeOrSucceed(base::WeakPtr<T> ptr,IndexedDBTransaction::Operation operation,IndexedDBTransaction * transaction)25 leveldb::Status InvokeOrSucceed(base::WeakPtr<T> ptr,
26 IndexedDBTransaction::Operation operation,
27 IndexedDBTransaction* transaction) {
28 if (ptr)
29 return std::move(operation).Run(transaction);
30 return leveldb::Status::OK();
31 }
32
33 template <typename R>
AbortCallback(base::WeakPtr<IndexedDBTransaction> transaction)34 R AbortCallback(base::WeakPtr<IndexedDBTransaction> transaction) {
35 if (transaction)
36 transaction->IncrementNumErrorsSent();
37 IndexedDBDatabaseError error(blink::mojom::IDBException::kIgnorableAbortError,
38 "Backend aborted error");
39 return R::Struct::NewErrorResult(
40 blink::mojom::IDBError::New(error.code(), error.message()));
41 }
42
43 template <typename R>
CreateAbortCallback(base::WeakPtr<IndexedDBTransaction> transaction)44 base::OnceCallback<R()> CreateAbortCallback(
45 base::WeakPtr<IndexedDBTransaction> transaction) {
46 return base::BindOnce(&AbortCallback<R>, std::move(transaction));
47 }
48
49 // CallbackAbortOnDestruct wraps a callback in a class with a destructor that
50 // invokes that callback. When the CallbackAbortOnDestruct is instantiated,
51 // it expects a separate callback that, when called at destruct, will return
52 // the arguments that should be passed to the wrapped callback.
53 //
54 // This class is loosely based on //mojo/public/cpp/bindings/callback_helpers.h
55 // WrapCallbackWithDefaultInvokeIfNotRun. The difference is that the destructor
56 // calls |callback_| with args it gets on destruct rather than using static args
57 // given when the wrapper is created.
58 template <typename T, typename R>
59 class CallbackAbortOnDestruct {
60 public:
CallbackAbortOnDestruct(T callback,base::WeakPtr<IndexedDBTransaction> transaction)61 CallbackAbortOnDestruct(T callback,
62 base::WeakPtr<IndexedDBTransaction> transaction)
63 : callback_(std::move(callback)),
64 args_at_destroy_(CreateAbortCallback<R>(transaction)),
65 called_(false) {}
~CallbackAbortOnDestruct()66 ~CallbackAbortOnDestruct() {
67 if (called_)
68 return;
69 R args = std::move(args_at_destroy_).Run();
70 std::move(callback_).Run(std::move(args));
71 }
72
Run(R ptr)73 void Run(R ptr) {
74 called_ = true;
75 std::move(callback_).Run(std::move(ptr));
76 }
77
78 private:
79 T callback_;
80 base::OnceCallback<R()> args_at_destroy_;
81 bool called_;
82 DISALLOW_COPY_AND_ASSIGN(CallbackAbortOnDestruct);
83 };
84
85 } // namespace indexed_db_callback_helpers_internal
86
87 // CreateCallbackAbortOnDestruct is a helper function to create an instance
88 // of CallbackAbortOnDestruct that returns a callback. By using this helper
89 // function, the wrapping callback can exist with the same type signature as
90 // the wrapped callback.
91 template <typename T, typename R>
CreateCallbackAbortOnDestruct(T cb,base::WeakPtr<IndexedDBTransaction> transaction)92 T CreateCallbackAbortOnDestruct(
93 T cb,
94 base::WeakPtr<IndexedDBTransaction> transaction) {
95 return base::BindOnce(
96 &indexed_db_callback_helpers_internal::CallbackAbortOnDestruct<T, R>::Run,
97 std::make_unique<
98 indexed_db_callback_helpers_internal::CallbackAbortOnDestruct<T, R>>(
99 std::move(cb), std::move(transaction)));
100 }
101
102 // This allows us to bind a function with a return value to a weak ptr, and if
103 // the weak pointer is invalidated then we just return a default (success).
104 template <typename T, typename Functor, typename... Args>
BindWeakOperation(Functor && functor,base::WeakPtr<T> ptr,Args &&...args)105 IndexedDBTransaction::Operation BindWeakOperation(Functor&& functor,
106 base::WeakPtr<T> ptr,
107 Args&&... args) {
108 DCHECK(ptr);
109 T* raw_ptr = ptr.get();
110 return base::BindOnce(
111 &indexed_db_callback_helpers_internal::InvokeOrSucceed<T>, std::move(ptr),
112 base::BindOnce(std::forward<Functor>(functor), base::Unretained(raw_ptr),
113 std::forward<Args>(args)...));
114 }
115
116 } // namespace content
117
118 #endif // CONTENT_BROWSER_INDEXED_DB_INDEXED_DB_CALLBACK_HELPERS_H_
119