chromium/third_party/blink/renderer/platform/heap/weak_cell.h

// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_WEAK_CELL_H_
#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_WEAK_CELL_H_

#include <type_traits>

#include "base/functional/bind_internal.h"
#include "base/types/pass_key.h"
#include "third_party/blink/renderer/platform/heap/cross_thread_handle.h"
#include "third_party/blink/renderer/platform/heap/garbage_collected.h"
#include "third_party/blink/renderer/platform/heap/member.h"
#include "third_party/blink/renderer/platform/heap/persistent.h"
#include "third_party/blink/renderer/platform/heap/visitor.h"
#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"

namespace blink {

template <typename T>
class WeakCellFactory;

// A `WeakCell<T>` provides a GC-safe pattern for classes that want to:
// - expose weak references to themselves
// - invalidate the weak references *before* the object becomes unreachable.
//
// This differs from `WeakMember<T>` in the last point, as `WeakMember<T>` only
// becomes implicitly null after the referenced `T` is no longer reachable. In
// Chrome, a common use of early invalidation is to cancel callbacks that have
// not yet run.
//
// If early invalidation is not needed, please use `WeakMember<T>`!
//
// Like many Oilpan types, this class is thread-unsafe.
//
// Note: This is the GC-safe version of `WeakPtrFactory<T>` + `WeakPtr<T>`.
// `WeakPtrFactory<T>` + `WeakPtr<T>` are GC-unsafe and should not be embedded
// in objects that live on the Oilpan heap.
template <typename T>
class WeakCell : public GarbageCollected<WeakCell<T>> {};

// A `WeakCellFactory<T>` vends out a pointer to a `WeakCell<T>`, and allows the
// owning class to invalidate `WeakCell<T>`s that have already been handed out.
//
// Usage overview:
//
// class DatabaseScheduler : public GarbageCollected<DatabaseScheduler> {
//  public:
//   ...
//
//   void DoWork();
//   void CancelWork();
//
//  private:
//   // Note: field ordering for `WeakCellFactory` does not matter, and it does
//   // *not* have to be the last field in a class.
//   WeakCellFactory<DatabaseScheduler> weak_factory_{this};
//   // Note: this is *not* a cross-thread task runner. In Blink, many task
//   // queues are multiplexed onto one thread.
//   scoped_refptr<base::TaskRunner> db_task_queue;
// };
//
// void DatabaseScheduler::DoWork() {
//   // IMPORTANT: the `WrapPersistent()` around the `WeakCell<T>` argument is
//   // mandatory, as `WeakCell<T>` itself is allocated on the Oilpan heap.
//   db_task_queue_->PostTask(
//       FROM_HERE,
//       base::BindOnce(&DatabaseScheduler::DoRealWork,
//                      WrapPersistent(weak_factory_.GetWeakCell())));
// }
//
// void DatabaseScheduler::CancelWork() {
//   // Any already-posted but not-yet-run tasks using a `WeakCell<T>` as the
//   // receiver will not run.
//   // However, any subsequent calls to `DoWork()` above *will* schedule new
//   // callbacks that will run unless `CancelWork()` is called again.
//   weak_factory_.Invalidate();
// }
template <typename T>
class WeakCellFactory {};

}  // namespace blink

namespace base {

IsWeakReceiver<blink::Persistent<blink::WeakCell<T>>>;

BindUnwrapTraits<blink::Persistent<blink::WeakCell<T>>>;

MaybeValidTraits<blink::Persistent<blink::WeakCell<T>>>;

IsWeakReceiver<blink::UnwrappingCrossThreadHandle<blink::WeakCell<T>>>;

BindUnwrapTraits<blink::UnwrappingCrossThreadHandle<blink::WeakCell<T>>>;

MaybeValidTraits<blink::UnwrappingCrossThreadHandle<blink::WeakCell<T>>>;

}  // namespace base

#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_WEAK_CELL_H_