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