// 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_