chromium/chromecast/base/component/component_internal.h

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

#ifndef CHROMECAST_BASE_COMPONENT_COMPONENT_INTERNAL_H_
#define CHROMECAST_BASE_COMPONENT_COMPONENT_INTERNAL_H_

#include "base/check.h"
#include "base/functional/callback.h"
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
#include "base/threading/thread_checker.h"

namespace chromecast {

template <typename C>
class WeakReference;

class ComponentBase;

namespace subtle {

class WeakReferenceBase;

// Manages thread-safe dependency counting. Instances of this class are
// RefCountedThreadSafe since they must live as long as any dependent.
class DependencyCount;

// Base class for strong dependencies. A strong dependency is tied to a
// specific dependent component instance. This allows dependents to be
// disabled before the component they depend on. May be used on any thread.
class DependencyBase {
 public:
  DependencyBase(const WeakReferenceBase& dependency, ComponentBase* dependent);

  DependencyBase(const DependencyBase&) = delete;
  DependencyBase& operator=(const DependencyBase&) = delete;

  ~DependencyBase();

  void StartUsing();
  void StopUsing();
  bool DependsOn(ComponentBase* component);

 protected:
  ComponentBase* const dependent_;
  ComponentBase* dependency_;

 private:
  friend class DependencyCount;
  friend class WeakReferenceBase;

  void Ready(ComponentBase* dependency);
  void Disable();

  const scoped_refptr<DependencyCount> counter_;
  base::ThreadChecker thread_checker_;
};

// Base class for weak dependencies. Weak dependencies cannot be used
// directly; they must be converted to a strong dependency or a temp
// dependency first. May be converted on any thread.
class WeakReferenceBase {
 protected:
  friend class DependencyBase;

  explicit WeakReferenceBase(const ComponentBase& dependency);
  explicit WeakReferenceBase(const DependencyBase& dependency);
  WeakReferenceBase(const WeakReferenceBase& other);
  WeakReferenceBase(WeakReferenceBase&& other);
  ~WeakReferenceBase();

  const scoped_refptr<DependencyCount> counter_;
};

// Base class for temp dependencies. Temp dependencies are meant for
// short-term use only, but can be used from any thread.
class ScopedReferenceBase {
 protected:
  explicit ScopedReferenceBase(const scoped_refptr<DependencyCount>& counter);
  ScopedReferenceBase(ScopedReferenceBase&& other);
  ~ScopedReferenceBase();

  const scoped_refptr<DependencyCount> counter_;
  ComponentBase* dependency_;
};

// This class is not intended to be long-lived, and should not be declared as
// a variable type (eg, don't use it as a member variable). Instead, use auto
// (see WeakReference::Try() for an example).
template <typename C>
class Ref_DO_NOT_DECLARE : public ScopedReferenceBase {
 public:
  Ref_DO_NOT_DECLARE(Ref_DO_NOT_DECLARE&& other) = default;

  C* operator->() const {
    DCHECK(dependency_);
    return static_cast<C*>(dependency_);
  }

  explicit operator bool() const { return (dependency_ != nullptr); }

 private:
  friend class WeakReference<C>;

  explicit Ref_DO_NOT_DECLARE(const scoped_refptr<DependencyCount>& counter)
      : ScopedReferenceBase(counter) {}

  Ref_DO_NOT_DECLARE(const Ref_DO_NOT_DECLARE& other) = delete;
  Ref_DO_NOT_DECLARE& operator=(const Ref_DO_NOT_DECLARE& rhs) = delete;
  Ref_DO_NOT_DECLARE& operator=(Ref_DO_NOT_DECLARE&& rhs) = delete;
};

}  // namespace subtle
}  // namespace chromecast

#endif  // CHROMECAST_BASE_COMPONENT_COMPONENT_INTERNAL_H_