chromium/ui/base/interaction/element_identifier.h

// Copyright 2021 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_INTERACTION_ELEMENT_IDENTIFIER_H_
#define UI_BASE_INTERACTION_ELEMENT_IDENTIFIER_H_

#include <stdint.h>

#include <ostream>
#include <set>

#include "base/component_export.h"
#include "base/memory/raw_ptr_exclusion.h"
#include "base/numerics/safe_conversions.h"
#include "ui/base/class_property.h"

// Overview:
// ElementIdentifier provides a named opaque value that can be used to identify
// individual (or potentially groups of) elements in the UI.
//
// Unique identifier constants must be both declared and defined. To create a
// publicly-visible identifier, declare a new unique value in your .h file,
// with the following; the string name of the identifier will be the same as
// the identifier's C++ identifier (in this case, kMyIdentifierName):
//
//   DECLARE_ELEMENT_IDENTIFIER_VALUE(kMyIdentifierName);
//
// If the identifier should be exported, declare it with the following instead:
//
//   DECLARE_EXPORTED_ELEMENT_IDENTIFIER_VALUE(MY_EXPORT, kMyIdentifierName);
//
// Regardless of whether the declared identifier is exported or not, make sure
// it is defined in the corresponding .cc file:
//
//   DEFINE_ELEMENT_IDENTIFIER_VALUE(kMyIdentifierName);
//
// If you want to add an identifier as a class member, use the following; the
// string name of the identifier will be in the form
// "MyClass::kMyIdentifierName":
//
//   class MyClass {
//     DECLARE_CLASS_ELEMENT_IDENTIFIER_VALUE(kMyIdentifierName);
//   };
//
// Then in the corresponding .cc file, add the following:
//
//   DEFINE_CLASS_ELEMENT_IDENTIFIER_VALUE(MyClass, kMyIdentifierValue);
//
// If you want to create an identifier local to a .cc file or to a method, you
// can instead use the following all-in-one declaration. Note that this is only
// really useful in tests and that the resulting identifier name is mangled
// with the file and line number:
//
//   DEFINE_LOCAL_ELEMENT_IDENTIFIER_VALUE(kMyIdentifierName);
//
// That's it! You can now initialize an ElementIdentifier using this value, or
// pass it directly to a method:
//
//   ElementIdentifier my_id = kMyIdentifierName;
//   ElementIdentifier my_id2 = my_id;
//   MyFuncThatTakesAnIdentifier(kMyIdentifierName);
//   MyFuncThatTakesAnIdentifier(my_id2);
//
// ElementIdentifier behaves more or less like other mutable primitive types; it
// is default-constructable (producing a null value) and supports the ==, !=, <,
// !, and (bool) operators as well as assignment and copy [1]. This means you
// can use ElementIdentifier as a key in std::set and std::map, and it is safe
// to use in both DCHECK and test assertions:
//
//   ElementIdentifier id1;
//   ElementIdentifier id2 = kMyIdentifierName;
//   std::map<ElementIdentifier, int> map;
//   map.emplace(id2, 4);
//   DCHECK(!id1);
//   EXPECT_TRUE(static_cast<bool>(id2));
//   DCHECK_NE(id1, id2);
//   EXPECT_FALSE(base::Contains(map, id1));
//   ASSERT_EQ(4, map[id2]);
//
// -----
//
// [1] Please note that while operator < will provide a strict ordering, the
//   specific order of two ElementIdentifier constants may vary by build and
//   should not be relied upon; operator < is only provided for compatibility
//   with sorted STL containers.

ui  // namespace ui

// Declaring identifiers outside a scope:
//
// Note: if you need to use the identifier outside the current component, use
// DECLARE/DEFINE_EXPORTED_... below.

// Use this code in the .h file to declare a new identifier.
#define DECLARE_ELEMENT_IDENTIFIER_VALUE(IdentifierName)

// Use this code in the .cc file to define a new identifier.
#define DEFINE_ELEMENT_IDENTIFIER_VALUE(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_ELEMENT_IDENTIFIER_VALUE(ExportName, IdentifierName)

// Use this code in the .cc file to define a new exported identifier.
#define DEFINE_EXPORTED_ELEMENT_IDENTIFIER_VALUE(IdentifierName)

// 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_ELEMENT_IDENTIFIER_VALUE(IdentifierName)

// Use this code in your class definition .cc file to define the member
// variables
#define DEFINE_CLASS_ELEMENT_IDENTIFIER_VALUE(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_ELEMENT_IDENTIFIER_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_ELEMENT_IDENTIFIER_VALUE(File, Line, IdentifierName)

// 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_ELEMENT_IDENTIFIER_VALUE(IdentifierName)

#endif  // UI_BASE_INTERACTION_ELEMENT_IDENTIFIER_H_