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

#ifndef UI_BASE_IDENTIFIER_UNIQUE_IDENTIFIER_H_
#define UI_BASE_IDENTIFIER_UNIQUE_IDENTIFIER_H_

#include <ostream>
#include <set>
#include <string>

#include "base/component_export.h"
#include "base/memory/raw_ptr_exclusion.h"
#include "base/types/pass_key.h"

// UniqueIdentifier provides a named, opaque, constexpr value that can be used
// to identify things.
//
// UniqueIdentifier is not used directly; rather, types are created from it.
// See README.md for detailed usage instructions.

namespace ui::internal {

// Defines the underlying value that an UniqueIdentifier holds (namely, the
// address of an instance of this class). Because these objects are only
// declared statically, the value of an UniqueIdentifier is always valid and
// two UniqueIdentifiers are equal if and only if they hold the address of the
// same instance of this class.
//
// Instances of this object are named for logging and retrieval purposes only,
// the value of name() should never be used for any other purpose.
struct UniqueIdentifierProvider {
  // The unique name of the identifier, which corresponds to the name of the
  // identifier constant in code in predictable ways (see README.md).
  const char* const name;
};

template <typename T, const char* N, typename... F>
class UniqueIdentifierImpl;

// Holds a globally-unique, value-typed identifier from a set of identifiers
// which can be declared in any static scope.
//
// This type is comparable and supports operator bool and negation, where
// default-constructed instances have false value and all other values evaluate
// as true. It can also be used as the key in std::set, std::map, and similar
// collections.
class COMPONENT_EXPORT(UI_BASE_IDENTIFIER) UniqueIdentifier final {
 public:
  // Creates a null identifier.
  constexpr UniqueIdentifier() = default;

  // Avoid this constructor - it is used internally by the
  // DECLARE_IDENTIFIER_VALUE() macro.
  explicit constexpr UniqueIdentifier(
      const internal::UniqueIdentifierProvider* provider)
      : handle_(provider) {}

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

  constexpr bool operator!() const { return !handle_; }

  friend constexpr bool operator==(const UniqueIdentifier&,
                                   const UniqueIdentifier&) = default;

  // TODO(crbug.com/333028921): Operator < cannot be constexpr because memory
  // order of Impl objects is not strictly known at compile time. Fix this...
  // somehow? Possibilities include compile-time hashing of identifier string.
  friend auto operator<=>(const UniqueIdentifier&,
                          const UniqueIdentifier&) = default;

  // Retrieves the identifier name, or the empty string if none.
  std::string GetName() const;

  // Retrieve a known UniqueIdentifier by name. An UniqueIdentifier is *known*
  // if the value of the identifier has been serialized using GetRawValue() or
  // GetName().
  static UniqueIdentifier FromName(const char* name);

  // Included for interoperability with PropertyHandler. Retrieves a unique
  // identifier from the result of calling GetRawValue(). The `value` passed in
  // MUST either have been generated by calling GetRawValue() or be zero (this
  // is strictly enforced even in release builds).
  static UniqueIdentifier FromRawValue(intptr_t value);

  // Registers a non-null identifier as known. Has no effect if the identifier
  // is already registered. Call only when you want to force the identifier to
  // be registered but aren't calling `GetName()` or `GetRawValue()`.
  static void RegisterKnownIdentifier(UniqueIdentifier element_dentifier);

  // Clears out the cache of known identifiers.
  static void ClearKnownIdentifiersForTesting();

 private:
  using KnownIdentifiers = std::set<const internal::UniqueIdentifierProvider*>;

  template <typename T, const char* N, typename... F>
  friend class internal::UniqueIdentifierImpl;

  // Used only by UniqueIdentifierImpl.
  intptr_t GetRawValue() const;

  // Returns the singleton set of known identifiers.
  static KnownIdentifiers& GetKnownIdentifiers();

  // The value of the identifier. Because all non-null values point to static
  // UniqueIdentifierProvider objects this can be treated as a value from a set
  // of unique, opaque handles. RAW_PTR_EXCLUSION: Since all
  // UniqueIdentifierProvider instances are statically-allocated, this pointer
  // can never dangle.
  RAW_PTR_EXCLUSION const internal::UniqueIdentifierProvider* handle_ = nullptr;
};

// Class which is used for actual identifiers. These use the same underlying
// data structure but are not interchangeable; they function much like
// base::StrongAlias.
//
// Do not create instance of this class directly; instead, use the macro
// `DECLARE_UNIQUE_IDENTIFIER_TYPE()` to create a concrete type (see below).
template <typename T, const char* N, typename... F>
class UniqueIdentifierImpl {
 public:
  constexpr explicit operator bool() const { return static_cast<bool>(id_); }

  constexpr bool operator!() const { return !id_; }

  friend constexpr bool operator==(const UniqueIdentifierImpl&,
                                   const UniqueIdentifierImpl&) = default;

  // TODO(crbug.com/333028921): Operator < cannot be constexpr because memory
  // order of Impl objects is not strictly known at compile time. Fix this...
  // somehow? Possibilities include compile-time hashing of identifier string.
  friend auto operator<=>(const UniqueIdentifierImpl&,
                          const UniqueIdentifierImpl&) = default;

  // Retrieves the element name, or the empty string if none.
  std::string GetName() const { return id_.GetName(); }

  // Retrieve a known ElementIdentifier by name. An ElementIdentifier is *known*
  // if a TrackedElement has been created with the id, or if the value of the
  // identifier has been serialized using GetRawValue() or GetName().
  static T FromName(const char* name) {
    T temp;
    temp.id_ = UniqueIdentifier::FromName(name);
    return temp;
  }

  // Get the raw value. Only accessible by classes in `F`.
  template <typename U>
    requires(false || (std::same_as<U, F> || ...))
  intptr_t GetRawValue(base::PassKey<U>) const {
    return id_.GetRawValue();
  }

  // Included for interoperability with PropertyHandler. Retrieves an element
  // identifier from the result of calling GetRawValue(). The `value` passed in
  // MUST either have been generated by calling GetRawValue() or be zero (this
  // is strictly enforced even in release builds).
  static T FromRawValue(intptr_t value) {
    T temp;
    temp.id_ = UniqueIdentifier::FromRawValue(value);
    return temp;
  }

  // Retrieve the identifier. Only accessible by classes in `F`.
  template <typename U>
    requires(false || (std::same_as<U, F> || ...))
  UniqueIdentifier GetIdentifier(base::PassKey<U>) const {
    return id_;
  }

 protected:
  constexpr UniqueIdentifierImpl() = default;
  explicit constexpr UniqueIdentifierImpl(
      const internal::UniqueIdentifierProvider* provider)
      : id_(provider) {}

 private:
  UniqueIdentifier id_;
};

// Concept/constraint requiring `A` to be a strict ancestor of `C`.
template <typename A, typename C>
concept IsStrictAncestorOf = std::derived_from<C, A> && !std::same_as<C, A>;

// If you need to ensure that a specific type is a strongly-typed identifier,
// you can require this concept.
template <typename T>
concept IsUniqueIdentifierImpl = requires(T t) {
  { UniqueIdentifierImpl{t} } -> IsStrictAncestorOf<T>;
};

// Convenience methods for debugging and printing.

template <typename T, const char* N, typename... F>
void PrintTo(UniqueIdentifierImpl<T, N, F...> id, std::ostream* os) {
  *os << N << ": " << id.GetName();
}

template <typename T, const char* N, typename... F>
std::ostream& operator<<(std::ostream& os,
                         UniqueIdentifierImpl<T, N, F...> id) {
  PrintTo(id, &os);
  return os;
}

COMPONENT_EXPORT(UI_BASE_IDENTIFIER)
extern void PrintTo(UniqueIdentifier identifier, std::ostream* os);

COMPONENT_EXPORT(UI_BASE_IDENTIFIER)
extern std::ostream& operator<<(std::ostream& os,
                                UniqueIdentifier element_identifier);

}  // namespace ui::internal

// Macros for creating new identifier types and values.

// Defines IdentifierType as a strongly-typed unique identifier. The variadic
// args are the classes (if any) which can access PassKey-protected members of
// UniqueIdentifierImpl.
#define DECLARE_UNIQUE_IDENTIFIER_TYPE(IdentifierType, ...)                \
  static constexpr char k##IdentifierType##ClassName[] = #IdentifierType;  \
  class IdentifierType final                                               \
      : public ::ui::internal::UniqueIdentifierImpl<                       \
            IdentifierType, k##IdentifierType##ClassName, ##__VA_ARGS__> { \
   public:                                                                 \
    constexpr IdentifierType() = default;                                  \
    explicit constexpr IdentifierType(                                     \
        const ::ui::internal::UniqueIdentifierProvider* provider)          \
        : UniqueIdentifierImpl(provider) {}                                \
  }

// Use this code in the .h file to declare a new identifier.
// IdentifierType must be qualified if outside the current scope (e.g. it is a
// class member).
#define DECLARE_UNIQUE_IDENTIFIER_VALUE(IdentifierType, IdentifierName) \
  extern const ::ui::internal::UniqueIdentifierProvider                 \
      IdentifierName##Provider;                                         \
  inline constexpr IdentifierType IdentifierName(&IdentifierName##Provider)

// Use this code in the .cc file to define a new identifier.
#define DEFINE_UNIQUE_IDENTIFIER_VALUE(IdentifierType, IdentifierName)      \
  const ::ui::internal::UniqueIdentifierProvider IdentifierName##Provider { \
    #IdentifierName                                                         \
  }

// Declaring identifiers that can be used in other components:
//
// Note: unlike other declarations, this identifier will not be constexpr in
// most cases.

// Use this code in the .h file to declare a new exported identifier.
#define DECLARE_EXPORTED_UNIQUE_IDENTIFIER_VALUE(ExportName, IdentifierType, \
                                                 IdentifierName)             \
  ExportName extern const ::ui::internal::UniqueIdentifierProvider           \
      IdentifierName##Provider;                                              \
  ExportName extern const IdentifierType IdentifierName

// Use this code in the .cc file to define a new exported identifier.
#define DEFINE_EXPORTED_UNIQUE_IDENTIFIER_VALUE(IdentifierType,            \
                                                IdentifierName)            \
  const ::ui::internal::UniqueIdentifierProvider IdentifierName##Provider{ \
      #IdentifierName};                                                    \
  const IdentifierType IdentifierName(&IdentifierName##Provider)

// Declaring identifiers in a class:

// Use this code in your class declaration in its .h file to declare an
// identifier that is scoped to your class.
#define DECLARE_CLASS_UNIQUE_IDENTIFIER_VALUE(IdentifierType, IdentifierName) \
  static const ::ui::internal::UniqueIdentifierProvider                       \
      IdentifierName##Provider;                                               \
  static constexpr IdentifierType IdentifierName {                            \
    &IdentifierName##Provider                                                 \
  }

// Use this code in your class definition .cc file to define the member
// variables
#define DEFINE_CLASS_UNIQUE_IDENTIFIER_VALUE(ClassName, IdentifierType,     \
                                             IdentifierName)                \
  const ::ui::internal::UniqueIdentifierProvider                            \
      ClassName::IdentifierName##Provider{#ClassName "::" #IdentifierName}; \
  constexpr IdentifierType ClassName::IdentifierName

// Declaring local identifiers in functions, class methods, or local to a .cc
// file (often used in tests). File and line are included to guarantee that the
// text of the name generated is unique, though that makes the exact text
// harder to predict.

// This helper macro is required because of how __LINE__ is handled when passed
// between macros, you need an intermediate macro in order to stringify it.
// DO NOT CALL DIRECTLY; used by DEFINE_LOCAL_ELEMENT_IDENTIFIER_VALUE().
#define LOCAL_UNIQUE_IDENTIFIER_NAME(File, Line, Name) \
  File "::" #Line "::" #Name

// Use this code to declare a local identifier from within a macro; you should
// pass the __FILE__ and __LINE__ values for `File` and `Line`. The name will be
// mangled with the file and line so that it can be used in local or module
// scope (typically in tests) without having to worry about name collisions.
#define DEFINE_MACRO_LOCAL_UNIQUE_IDENTIFIER_VALUE(File, Line, IdentifierType, \
                                                   IdentifierName)             \
  static constexpr ::ui::internal::UniqueIdentifierProvider                    \
      IdentifierName##Provider{                                                \
          LOCAL_UNIQUE_IDENTIFIER_NAME(File, Line, IdentifierName)};           \
  static constexpr IdentifierType IdentifierName(&IdentifierName##Provider)

// Use this code to declare a local identifier in a function body or module
// scope. The name will be mangled with the file and line so that it can be used
// (typically in tests) without having to worry about name collisions.
#define DEFINE_LOCAL_UNIQUE_IDENTIFIER_VALUE(IdentifierType, IdentifierName) \
  DEFINE_MACRO_LOCAL_UNIQUE_IDENTIFIER_VALUE(__FILE__, __LINE__,             \
                                             IdentifierType, IdentifierName)

#endif  // UI_BASE_IDENTIFIER_UNIQUE_IDENTIFIER_H_
