#ifndef UI_VIEWS_METADATA_VIEW_FACTORY_H_
#define UI_VIEWS_METADATA_VIEW_FACTORY_H_
#include <concepts>
#include <functional>
#include <map>
#include <memory>
#include <optional>
#include <string_view>
#include <type_traits>
#include <utility>
#include <variant>
#include <vector>
#include "base/functional/bind.h"
#include "base/macros/concat.h"
#include "base/macros/remove_parens.h"
#include "base/memory/raw_ptr.h"
#include "ui/base/class_property.h"
#include "ui/base/metadata/base_type_conversion.h"
#include "ui/views/metadata/view_factory_internal.h"
#include "ui/views/view_utils.h"
#include "ui/views/views_export.h"
namespace views {
template <typename Builder>
class BaseViewBuilderT : public internal::ViewBuilderCore {
public:
using ViewClass_ = typename internal::ViewClassTrait<Builder>::ViewClass_;
private:
using OwnedPtr = std::unique_ptr<ViewClass_>;
using Ptr = raw_ptr<ViewClass_>;
using ViewStorage = std::variant<OwnedPtr, Ptr>;
public:
explicit BaseViewBuilderT(OwnedPtr view = std::make_unique<ViewClass_>())
: view_(std::move(view)) {
CHECK(std::get<OwnedPtr>(view_));
}
explicit BaseViewBuilderT(ViewClass_* view) : view_(view) {
CHECK(std::get<Ptr>(view_));
}
template <typename OtherBuilder>
requires(!std::same_as<Builder, OtherBuilder> &&
std::convertible_to<
typename BaseViewBuilderT<OtherBuilder>::ViewClass_*,
ViewClass_*>)
BaseViewBuilderT(BaseViewBuilderT<OtherBuilder>&& other)
: view_(
std::visit([](auto&& view) { return ViewStorage(std::move(view)); },
std::move(other.view_))),
configure_callbacks_(
ConvertCallbacks(std::move(other.configure_callbacks_))),
after_build_callbacks_(
ConvertCallbacks(std::move(other.after_build_callbacks_))) {}
BaseViewBuilderT(BaseViewBuilderT&&) = default;
BaseViewBuilderT& operator=(BaseViewBuilderT&&) = default;
~BaseViewBuilderT() override = default;
template <typename Child>
Builder& AddChild(Child&& child) & {
children_.emplace_back(std::make_pair(child.Release(), std::nullopt));
return *static_cast<Builder*>(this);
}
template <typename Child>
Builder&& AddChild(Child&& child) && {
return std::move(this->AddChild(std::move(child)));
}
template <typename Child>
Builder& AddChildAt(Child&& child, size_t index) & {
children_.emplace_back(std::make_pair(child.Release(), index));
return *static_cast<Builder*>(this);
}
template <typename Child>
Builder&& AddChildAt(Child&& child, size_t index) && {
return std::move(this->AddChildAt(std::move(child), index));
}
template <typename Child, typename... Types>
Builder& AddChildren(Child&& child, Types&&... args) & {
return AddChildrenImpl(&child, &args...);
}
template <typename Child, typename... Types>
Builder&& AddChildren(Child&& child, Types&&... args) && {
return std::move(this->AddChildrenImpl(&child, &args...));
}
template <typename T>
Builder& SetProperty(const ui::ClassProperty<T>* property,
ui::metadata::ArgType<T> value) & {
auto setter =
std::make_unique<internal::ClassPropertyValueSetter<ViewClass_, T>>(
property, value);
internal::ViewBuilderCore::AddPropertySetter(std::move(setter));
return *static_cast<Builder*>(this);
}
template <typename T>
Builder&& SetProperty(const ui::ClassProperty<T>* property,
ui::metadata::ArgType<T> value) && {
return std::move(this->SetProperty(property, value));
}
template <typename T>
Builder& SetProperty(const ui::ClassProperty<T*>* property,
ui::metadata::ArgType<T> value) & {
auto setter =
std::make_unique<internal::ClassPropertyMoveSetter<ViewClass_, T>>(
property, value);
internal::ViewBuilderCore::AddPropertySetter(std::move(setter));
return *static_cast<Builder*>(this);
}
template <typename T>
Builder&& SetProperty(const ui::ClassProperty<T*>* property,
ui::metadata::ArgType<T> value) && {
return std::move(this->SetProperty(property, value));
}
template <typename T>
Builder& SetProperty(const ui::ClassProperty<T*>* property, T&& value) & {
auto setter =
std::make_unique<internal::ClassPropertyMoveSetter<ViewClass_, T>>(
property, std::move(value));
internal::ViewBuilderCore::AddPropertySetter(std::move(setter));
return *static_cast<Builder*>(this);
}
template <typename T>
Builder&& SetProperty(const ui::ClassProperty<T*>* property, T&& value) && {
return std::move(this->SetProperty(property, value));
}
template <typename T>
Builder& SetProperty(const ui::ClassProperty<T*>* property,
std::unique_ptr<T> value) & {
auto setter =
std::make_unique<internal::ClassPropertyUniquePtrSetter<ViewClass_, T>>(
property, std::move(value));
internal::ViewBuilderCore::AddPropertySetter(std::move(setter));
return *static_cast<Builder*>(this);
}
template <typename T>
Builder&& SetProperty(const ui::ClassProperty<T*>* property,
std::unique_ptr<T> value) && {
return std::move(this->SetProperty(property, std::move(value)));
}
template <typename ViewPtr>
Builder& CopyAddressTo(ViewPtr* view_address) & {
*view_address = std::visit([](auto& view) { return view.get(); }, view_);
return *static_cast<Builder*>(this);
}
template <typename ViewPtr>
Builder&& CopyAddressTo(ViewPtr* view_address) && {
return std::move(this->CopyAddressTo(view_address));
}
template <typename T>
requires(std::convertible_to<ViewClass_*, T*>)
Builder& CustomConfigure(base::OnceCallback<void(T*)> configure_callback) & {
return AddCallbackImpl(std::move(configure_callback), configure_callbacks_);
}
template <typename T>
requires(std::convertible_to<ViewClass_*, T*>)
Builder&& CustomConfigure(
base::OnceCallback<void(T*)> configure_callback) && {
return std::move(this->CustomConfigure(std::move(configure_callback)));
}
template <typename T>
requires(std::convertible_to<ViewClass_*, T*>)
Builder& AfterBuild(base::OnceCallback<void(T*)> after_build_callback) & {
return AddCallbackImpl(std::move(after_build_callback),
after_build_callbacks_);
}
template <typename T>
requires(std::convertible_to<ViewClass_*, T*>)
Builder&& AfterBuild(base::OnceCallback<void(T*)> after_build_callback) && {
return std::move(this->AfterBuild(std::move(after_build_callback)));
}
[[nodiscard]] OwnedPtr Build() && {
CHECK(std::holds_alternative<OwnedPtr>(view_))
<< "Use `BuildChildren()` on `Builder`s of non-owned `View`s.";
auto view = std::get<OwnedPtr>(std::move(view_));
SetProperties(view.get());
DoCustomConfigure(view.get());
CreateChildren(view.get());
DoAfterBuild(view.get());
return view;
}
void BuildChildren() && {
CHECK(std::holds_alternative<Ptr>(view_))
<< "Use `Build()` on `Builder`s of owned `View`s.";
auto view = std::get<Ptr>(view_);
SetProperties(view);
DoCustomConfigure(view);
CreateChildren(view);
DoAfterBuild(view);
}
private:
template <typename T>
friend class BaseViewBuilderT;
using ConfigureCallback = base::OnceCallback<void(ViewClass_*)>;
template <typename T>
requires(!std::same_as<ViewClass_, T> &&
std::convertible_to<T*, ViewClass_*>)
static std::vector<ConfigureCallback> ConvertCallbacks(
std::vector<base::OnceCallback<void(T*)>> other_callbacks) {
std::vector<ConfigureCallback> callbacks;
callbacks.reserve(other_callbacks.size());
for (auto& callback : other_callbacks) {
callbacks.push_back(base::BindOnce(
[](base::OnceCallback<void(T*)> cb, ViewClass_* view) {
auto* const t = AsViewClass<T>(view);
CHECK(t);
std::move(cb).Run(t);
},
std::move(callback)));
}
return callbacks;
}
template <typename... Args>
Builder& AddChildrenImpl(Args*... args) & {
std::vector<internal::ViewBuilderCore*> children = {args...};
for (auto* child : children) {
children_.emplace_back(std::make_pair(child->Release(), std::nullopt));
}
return *static_cast<Builder*>(this);
}
template <typename T>
requires(std::convertible_to<ViewClass_*, T*>)
Builder& AddCallbackImpl(base::OnceCallback<void(T*)> callback,
std::vector<ConfigureCallback>& callbacks) & {
if constexpr (std::same_as<T, ViewClass_>) {
callbacks.push_back(std::move(callback));
} else {
callbacks.push_back(
base::BindOnce([](base::OnceCallback<void(T*)> cb,
ViewClass_* view) { std::move(cb).Run(view); },
std::move(callback)));
}
return *static_cast<Builder*>(this);
}
void DoCustomConfigure(ViewClass_* view) {
for (auto& cb : configure_callbacks_) {
std::move(cb).Run(view);
}
}
std::unique_ptr<View> DoBuild() override { return std::move(*this).Build(); }
void DoAfterBuild(ViewClass_* view) {
for (auto& cb : after_build_callbacks_) {
std::move(cb).Run(view);
}
}
ViewStorage view_;
std::vector<ConfigureCallback> configure_callbacks_;
std::vector<ConfigureCallback> after_build_callbacks_;
};
}
#define NUM_ARGS_IMPL(_1, _2, _3, N, ...) N
#define NUM_ARGS(...) NUM_ARGS_IMPL(__VA_ARGS__, 3, 2, 1)
#define DECL_PARAM1(type) type param1
#define DECL_PARAM2(type, ...) type param2, DECL_PARAM1(__VA_ARGS__)
#define DECL_PARAM3(type, ...) type param3, DECL_PARAM2(__VA_ARGS__)
#define DECL_PARAMS(...) \
BASE_CONCAT(DECL_PARAM, NUM_ARGS(__VA_ARGS__))(__VA_ARGS__)
#define PASS_PARAM1(type) static_cast<type>(param1)
#define PASS_PARAM2(type, ...) \
static_cast<type>(param2), PASS_PARAM1(__VA_ARGS__)
#define PASS_PARAM3(type, ...) \
static_cast<type>(param3), PASS_PARAM2(__VA_ARGS__)
#define PASS_PARAMS(...) \
BASE_CONCAT(PASS_PARAM, NUM_ARGS(__VA_ARGS__))(__VA_ARGS__)
#define CHECK_TEMPLATE_TYPES_SYNTAX(...) \
CHECK_TEMPLATE_TYPES_SYNTAX_EXPANDED(__VA_ARGS__)
#define CHECK_TEMPLATE_TYPES_SYNTAX_EXPANDED(...) \
static_assert( \
[] { \
constexpr auto a = std::string_view(#__VA_ARGS__); \
return a.length() >= 2 && a.front() == '<' && a.back() == '>'; \
}(), \
"Template type arg is not surrounded by angle brackets; did you supply " \
"multiple types without wrapping the whole arg in parens?")
#define BEGIN_VIEW_BUILDER(export, view_class, ancestor) \
template <typename BuilderT> \
class export view_class##BuilderT : public ancestor##BuilderT<BuilderT> { \
private: \
using ViewClass_ = view_class; \
\
public: \
view_class##BuilderT() = default; \
explicit view_class##BuilderT( \
typename ::views::internal::ViewClassTrait<BuilderT>::ViewClass_* \
view) \
: ancestor##BuilderT<BuilderT>(view) {} \
explicit view_class##BuilderT( \
std::unique_ptr< \
typename ::views::internal::ViewClassTrait<BuilderT>::ViewClass_> \
view) \
: ancestor##BuilderT<BuilderT>(std::move(view)) {} \
template <typename OtherBuilder> \
requires( \
!std::same_as<BuilderT, OtherBuilder> && \
std::convertible_to< \
typename ::views::BaseViewBuilderT<OtherBuilder>::ViewClass_*, \
ViewClass_*>) \
explicit view_class##BuilderT( \
::views::BaseViewBuilderT<OtherBuilder>&& other) \
: ancestor##BuilderT<BuilderT>(std::move(other)) {} \
view_class##BuilderT(view_class##BuilderT&&) = default; \
view_class##BuilderT& operator=(view_class##BuilderT&&) = default; \
~view_class##BuilderT() override = default;
#define VIEW_BUILDER_PROPERTY2(property_type, property_name) \
BuilderT& Set##property_name( \
::ui::metadata::ArgType<property_type> value)& { \
auto setter = std::make_unique<::views::internal::PropertySetter< \
ViewClass_, property_type, decltype(&ViewClass_::Set##property_name), \
&ViewClass_::Set##property_name>>(std::move(value)); \
::views::internal::ViewBuilderCore::AddPropertySetter(std::move(setter)); \
return *static_cast<BuilderT*>(this); \
} \
BuilderT&& Set##property_name( \
::ui::metadata::ArgType<property_type> value)&& { \
return std::move(this->Set##property_name(std::move(value))); \
}
#define VIEW_BUILDER_PROPERTY3(property_type, property_name, field_type) \
BuilderT& Set##property_name( \
::ui::metadata::ArgType<property_type> value)& { \
auto setter = std::make_unique<::views::internal::PropertySetter< \
ViewClass_, property_type, decltype(&ViewClass_::Set##property_name), \
&ViewClass_::Set##property_name, field_type>>(std::move(value)); \
::views::internal::ViewBuilderCore::AddPropertySetter(std::move(setter)); \
return *static_cast<BuilderT*>(this); \
} \
BuilderT&& Set##property_name( \
::ui::metadata::ArgType<property_type> value)&& { \
return std::move(this->Set##property_name(std::move(value))); \
}
#define VIEW_BUILDER_PROPERTY(...) \
NUM_ARGS_IMPL(__VA_ARGS__, VIEW_BUILDER_PROPERTY3, VIEW_BUILDER_PROPERTY2) \
(__VA_ARGS__)
#define VIEW_BUILDER_TEMPLATED_PROPERTY(template_types, property_name, ...) \
CHECK_TEMPLATE_TYPES_SYNTAX(BASE_REMOVE_PARENS(template_types)); \
template BASE_REMOVE_PARENS(template_types) \
BuilderT& Set##property_name(DECL_PARAMS(__VA_ARGS__))& { \
auto caller = std::make_unique<::views::internal::ClassMethodCaller< \
ViewClass_, \
decltype(static_cast<void (ViewClass_::*)(__VA_ARGS__)>( \
&ViewClass_::Set##property_name)), \
&ViewClass_::Set##property_name, __VA_ARGS__>>( \
PASS_PARAMS(__VA_ARGS__)); \
::views::internal::ViewBuilderCore::AddPropertySetter(std::move(caller)); \
return *static_cast<BuilderT*>(this); \
} \
template BASE_REMOVE_PARENS(template_types) \
BuilderT&& Set##property_name(DECL_PARAMS(__VA_ARGS__))&& { \
return std::move(this->Set##property_name(PASS_PARAMS(__VA_ARGS__))); \
}
#define VIEW_BUILDER_OVERLOAD_METHOD_CLASS(class_name, method_name, ...) \
BuilderT& method_name(DECL_PARAMS(__VA_ARGS__))& { \
auto caller = std::make_unique<::views::internal::ClassMethodCaller< \
ViewClass_, \
decltype(static_cast<void (class_name::*)(__VA_ARGS__)>( \
&ViewClass_::method_name)), \
&class_name::method_name, __VA_ARGS__>>(PASS_PARAMS(__VA_ARGS__)); \
::views::internal::ViewBuilderCore::AddPropertySetter(std::move(caller)); \
return *static_cast<BuilderT*>(this); \
} \
BuilderT&& method_name(DECL_PARAMS(__VA_ARGS__))&& { \
return std::move(this->method_name(PASS_PARAMS(__VA_ARGS__))); \
}
#define VIEW_BUILDER_OVERLOAD_METHOD(method_name, ...) \
VIEW_BUILDER_OVERLOAD_METHOD_CLASS(ViewClass_, method_name, __VA_ARGS__)
#define VIEW_BUILDER_METHOD(method_name, ...) \
template <typename... Args> \
BuilderT& method_name(Args&&... args)& { \
auto caller = std::make_unique<::views::internal::ClassMethodCaller< \
ViewClass_, decltype(&ViewClass_::method_name), \
&ViewClass_::method_name, __VA_ARGS__>>(std::forward<Args>(args)...); \
::views::internal::ViewBuilderCore::AddPropertySetter(std::move(caller)); \
return *static_cast<BuilderT*>(this); \
} \
template <typename... Args> \
BuilderT&& method_name(Args&&... args)&& { \
return std::move(this->method_name(std::forward<Args>(args)...)); \
}
#define VIEW_BUILDER_METHOD_ALIAS(builder_method, view_method, ...) \
template <typename... Args> \
BuilderT& builder_method(Args&&... args)& { \
auto caller = std::make_unique<::views::internal::ClassMethodCaller< \
ViewClass_, decltype(&ViewClass_::view_method), \
&ViewClass_::view_method, __VA_ARGS__>>(std::forward<Args>(args)...); \
::views::internal::ViewBuilderCore::AddPropertySetter(std::move(caller)); \
return *static_cast<BuilderT*>(this); \
} \
template <typename... Args> \
BuilderT&& builder_method(Args&&... args)&& { \
return std::move(this->builder_method(std::forward<Args>(args)...)); \
}
#define VIEW_BUILDER_VIEW_TYPE_PROPERTY(property_type, property_name) \
template <typename _View> \
BuilderT& Set##property_name(_View&& view)& { \
auto setter = std::make_unique<::views::internal::ViewBuilderSetter< \
ViewClass_, property_type, \
decltype(&ViewClass_::Set##property_name<property_type>), \
&ViewClass_::Set##property_name<property_type>>>(view.Release()); \
::views::internal::ViewBuilderCore::AddPropertySetter(std::move(setter)); \
return *static_cast<BuilderT*>(this); \
} \
template <typename _View> \
BuilderT&& Set##property_name(_View&& view)&& { \
return std::move(this->Set##property_name(std::move(view))); \
}
#define VIEW_BUILDER_VIEW_PROPERTY(property_type, property_name) \
template <typename _View> \
BuilderT& Set##property_name(_View&& view)& { \
auto setter = std::make_unique<::views::internal::ViewBuilderSetter< \
ViewClass_, property_type, decltype(&ViewClass_::Set##property_name), \
&ViewClass_::Set##property_name>>(view.Release()); \
::views::internal::ViewBuilderCore::AddPropertySetter(std::move(setter)); \
return *static_cast<BuilderT*>(this); \
} \
template <typename _View> \
BuilderT&& Set##property_name(_View&& view)&& { \
return std::move(this->Set##property_name(std::move(view))); \
}
#define VIEW_BUILDER_PROPERTY_DEFAULT(property_type, property_name, default) \
BuilderT& Set##property_name(::ui::metadata::ArgType<property_type> value = \
default)& { \
auto setter = std::make_unique<::views::internal::PropertySetter< \
ViewClass_, property_type, decltype(&ViewClass_::Set##property_name), \
&ViewClass_::Set##property_name>>(std::move(value)); \
::views::internal::ViewBuilderCore::AddPropertySetter(std::move(setter)); \
return *static_cast<BuilderT*>(this); \
} \
BuilderT&& Set##property_name(::ui::metadata::ArgType<property_type> value = \
default)&& { \
return std::move(this->Set##property_name(value)); \
}
#define END_VIEW_BUILDER };
#define DEFINE_VIEW_BUILDER(export, view_class) \
namespace views { \
template <> \
class export Builder<view_class> \
: public view_class##BuilderT<Builder<view_class>> { \
private: \
using ViewClass_ = view_class; \
\
public: \
Builder() = default; \
explicit Builder(ViewClass_* view) \
: view_class##BuilderT<Builder>(view) {} \
explicit Builder(std::unique_ptr<ViewClass_> view) \
: view_class##BuilderT<Builder>(std::move(view)) {} \
template <typename OtherBuilder> \
requires( \
!std::same_as<Builder, OtherBuilder> && \
std::convertible_to< \
typename ::views::BaseViewBuilderT<OtherBuilder>::ViewClass_*, \
ViewClass_*>) \
explicit Builder(::views::BaseViewBuilderT<OtherBuilder>&& other) \
: view_class##BuilderT<Builder>(std::move(other)) {} \
Builder(Builder&&) = default; \
Builder& operator=(Builder&&) = default; \
~Builder() = default; \
[[nodiscard]] std::unique_ptr<internal::ViewBuilderCore> Release() \
override { \
return std::make_unique<Builder>(std::move(*this)); \
} \
}; \
}
#endif