17#include <glaze/glaze.hpp>
29namespace morph::model::detail {
48 std::type_index action;
50 std::vector<ResultSlot> resultSlots;
54using ActionResultSlotMap = std::map<std::string, ActionResult, std::less<>>;
56namespace result_walker {
65template <
typename T,
typename Alloc>
66struct Element<std::vector<T, Alloc>> {
71struct Element<std::optional<T>> {
75template <
typename K,
typename V,
typename Compare,
typename Alloc>
76struct Element<std::
map<K, V, Compare, Alloc>> {
89consteval bool hasAnonymousName() {
90 constexpr std::string_view name = glz::type_name<T>;
91 return name.contains(
"(anonymous namespace)") || name.contains(
"{anonymous}") ||
92 name.contains(
"`anonymous namespace'") || name.contains(
"`anonymous-namespace'");
101concept Object = std::is_class_v<T> && !glz::custom_read<T> && !glz::custom_write<T> &&
102 (glz::glaze_object_t<T> || (glz::reflectable<T> && !hasAnonymousName<T>()));
108consteval bool mayHoldSlots() {
109 if constexpr (!std::is_void_v<typename Element<T>::type>) {
110 return mayHoldSlots<std::remove_cvref_t<typename Element<T>::type>>();
119 std::vector<ResultSlot> found;
121 std::vector<std::type_index> onPath;
125void visit(Walk& walk, std::string
const& path);
132template <
typename T, std::size_t... I>
133void visitMembers(Walk& walk, std::string
const& path, std::index_sequence<I...> ) {
135 [[maybe_unused]]
auto const member = [&]<std::size_t Index>() {
136 using Member = std::remove_cvref_t<decltype(morph::detail::reflectedMember<Index>(std::declval<T&>()))>;
137 if constexpr (mayHoldSlots<Member>()) {
138 constexpr std::string_view key = glz::reflect<T>::keys[Index];
139 result_walker::visit<Member>(walk, path.empty() ? std::string{key} : path +
"." + std::string{key});
142 (member.template operator()<I>(), ...);
150void visit(Walk& walk, std::string
const& path) {
151 if constexpr (!std::is_void_v<typename Element<T>::type>) {
152 result_walker::visit<std::remove_cvref_t<typename Element<T>::type>>(
walk, path);
153 }
else if constexpr (Object<T>) {
154 std::type_index
const self{
typeid(T)};
155 if (std::ranges::find(
walk.onPath, self) !=
walk.onPath.end()) {
158 walk.found.push_back(ResultSlot{.type =
self, .path = path});
159 walk.onPath.push_back(self);
160 visitMembers<T>(walk, path, std::make_index_sequence<glz::reflect<T>::size>{});
161 walk.onPath.pop_back();
178[[nodiscard]] std::vector<ResultSlot> walkResult() {
179 result_walker::Walk
walk;
180 if constexpr (!std::is_void_v<R>) {
181 if constexpr (result_walker::mayHoldSlots<std::remove_cvref_t<R>>()) {
182 result_walker::visit<std::remove_cvref_t<R>>(
walk, std::string{});
185 return std::move(
walk.found);
190inline ActionResultSlotMap& mutableActionResultSlots() {
191 static ActionResultSlotMap entries;
197inline ActionResultSlotMap
const& actionResultSlots() {
return mutableActionResultSlots(); }
201inline std::vector<std::string>& mutableActionResultConflicts() {
202 static std::vector<std::string> ids;
212inline std::vector<std::string>
const& actionResultConflicts() {
return mutableActionResultConflicts(); }
AnyHandle map(AnyHandle const &source, std::string const &name, std::type_identity_t< std::function< AnyHandle(Handle< E > const &)> > const &body)
A comprehension over a list, {"map": e, "as": "x", "to": e}.
constexpr Self self
The dialog or drawer a command list runs in.
Value walk(Value const &value, std::span< std::string const > path)
Reads a path out of a value: a record's field by name, a list's element by index.
The value glaze reads and writes under a reflected key.