morph
0.1.0
Asynchronous bridge between GUI thread and business models
Toggle main menu visibility
Loading...
Searching...
No Matches
session_common.hpp
Go to the documentation of this file.
1
// SPDX-License-Identifier: Apache-2.0
2
3
#pragma once
4
5
/// @file forms/detail/session_common.hpp
6
/// @brief Machinery shared by the two form session types: `morph::flows::FlowSession`
7
/// (ordered wizard steps) and `morph::forms::SectionSet` (unordered sections).
8
///
9
/// Both declare their units the same way — a registered action, a title, and
10
/// zero or more `Bind` prefill declarations — and both walk those declarations
11
/// to emit a schema document. Only the sequencing differs, so the declaration
12
/// vocabulary and the pack/tuple walkers live here rather than being written
13
/// twice.
14
15
#include <cstddef>
16
#include <glaze/glaze.hpp>
17
#include <string>
18
#include <string_view>
19
#include <tuple>
20
#include <type_traits>
21
#include <utility>
22
23
#include "
../forms.hpp
"
24
25
namespace
morph::forms {
26
27
/// @brief One `field -> "<ActionTypeId>.<field>"` prefill binding declared on a
28
/// wizard step or an unordered section.
29
///
30
/// A declaration, not a write. Nothing in the framework assigns a bound field:
31
/// `wizardSchemaJson`/`sectionGroupSchemaJson` emit it for a renderer, and the
32
/// captured value is read back through `resolved()`.
33
/// @tparam Field The action's field name to prefill.
34
/// @tparam Path Source path, `"<ActionTypeId>.<field>"`, into captured values.
35
template
<morph::forms::FixedString Field, morph::forms::FixedString Path>
36
struct
Bind
{
37
/// @brief The action field name this binding fills.
38
/// @return The declared field name.
39
[[nodiscard]]
static
constexpr
std::string_view
field
() noexcept {
return
Field.view(); }
40
41
/// @brief The source path into captured values.
42
/// @return The declared `"<ActionTypeId>.<field>"` path.
43
[[nodiscard]]
static
constexpr
std::string_view
path
() noexcept {
return
Path.view(); }
44
};
45
46
namespace
detail {
47
48
/// @brief Invokes `visitor.template operator()<std::tuple_element_t<I, Tuple>, I>()`
49
/// for every element of @p Tuple, in order.
50
/// @tparam Tuple A `std::tuple<...>` type (only its element types/arity are used).
51
/// @tparam Visitor Callable with a `template<typename Element, std::size_t I> operator()()`.
52
/// @param visitor Callable invoked once per tuple element.
53
template
<
typename
Tuple,
typename
Visitor>
54
// NOLINTNEXTLINE(cppcoreguidelines-missing-std-forward) — invoked once per element, never moved from
55
constexpr
void
forEachTupleElement(Visitor&& visitor) {
56
// NOLINTNEXTLINE(cppcoreguidelines-rvalue-reference-param-not-moved) — same: one call per element
57
[]<std::size_t... I>(std::index_sequence<I...>, Visitor&& innerVisitor) {
58
(innerVisitor.template operator()<std::tuple_element_t<I, Tuple>, I>(), ...);
59
}(std::make_index_sequence<std::tuple_size_v<Tuple>>{}, std::forward<Visitor>(visitor));
60
}
61
62
/// @brief Invokes `visitor.template operator()<T>()` for the pack element of
63
/// `Ts...` at runtime position @p index. A no-op when
64
/// `index >= sizeof...(Ts)`.
65
/// @tparam Ts The pack to index into.
66
/// @tparam Visitor Callable with a `template<typename T> operator()()`.
67
/// @param index 0-based position to visit.
68
/// @param visitor Callable invoked for the element at @p index.
69
template
<
typename
... Ts,
typename
Visitor>
70
// NOLINTNEXTLINE(cppcoreguidelines-missing-std-forward) — the visited element is a run-time choice
71
constexpr
void
forPackElement(std::size_t index, Visitor&& visitor) {
72
std::size_t i = 0;
73
(void)((i++ == index ? (visitor.template
operator
()<Ts>(),
true
) :
false
) || ...);
74
}
75
76
/// @brief Trait: `true` when every type in `Ts...` is pairwise distinct.
77
/// @tparam Ts Types to check for pairwise distinctness.
78
template
<
typename
... Ts>
79
struct
AllDistinct : std::true_type {};
80
81
/// @brief Recursive case: `T` distinct from every type in `Rest...`, and `Rest...` pairwise distinct.
82
/// @tparam T The type being checked against `Rest...`.
83
/// @tparam Rest The remaining types.
84
template
<
typename
T,
typename
... Rest>
85
struct
AllDistinct<T, Rest...> : std::bool_constant<(!std::is_same_v<T, Rest> && ...) && AllDistinct<Rest...>::value> {
86
};
87
88
/// @brief Writes each `Bind` in @p BindsTuple into @p node as `"<field>": "<path>"`.
89
///
90
/// A no-op for an empty tuple, so callers guard on arity only to avoid
91
/// materialising an empty `prefill` object.
92
/// @tparam BindsTuple `std::tuple<Bind<...>...>`.
93
/// @param node Destination JSON object node.
94
// NOLINTBEGIN(cppcoreguidelines-pro-bounds-avoid-unchecked-container-access) -- glaze DOM requires operator[]
95
template
<
typename
BindsTuple>
96
void
emitBindsInto(glz::generic_u64& node) {
97
forEachTupleElement<BindsTuple>([&]<
typename
BindT, std::size_t J>() {
98
static_cast<
void
>
(J);
99
node[std::string{BindT::field()}] = std::string{BindT::path()};
100
});
101
}
102
// NOLINTEND(cppcoreguidelines-pro-bounds-avoid-unchecked-container-access)
103
104
}
// namespace detail
105
}
// namespace morph::forms
forms.hpp
JSON-Forms-style schema generation for morph actions.
morph::forms::Bind
One field -> "<ActionTypeId>.<field>" prefill binding declared on a wizard step or an unordered secti...
Definition
session_common.hpp:36
morph::forms::Bind::path
static constexpr std::string_view path() noexcept
The source path into captured values.
Definition
session_common.hpp:43
morph::forms::Bind::field
static constexpr std::string_view field() noexcept
The action field name this binding fills.
Definition
session_common.hpp:39
morph
forms
detail
session_common.hpp
Generated by
1.17.0