Skip to content

Commit 68c179c

Browse files
committed
dynamic_invoke
1 parent dbf4504 commit 68c179c

1 file changed

Lines changed: 114 additions & 7 deletions

File tree

include/boost/http/server/detail/dynamic_invoke.hpp

Lines changed: 114 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -101,26 +101,133 @@ dynamic_invoke(
101101

102102
//------------------------------------------------
103103

104+
template<class F, class Tuple, std::size_t... I>
105+
auto
106+
apply_tuple_deref(
107+
F const& f,
108+
route_params& p,
109+
Tuple& t,
110+
std::index_sequence<I...>)
111+
{
112+
return f(p, *std::get<I>(t)...);
113+
}
114+
115+
//------------------------------------------------
116+
117+
/** Wraps a callable whose first parameter is `route_params&`
118+
and whose remaining parameters are resolved from
119+
@ref route_params::route_data at dispatch time.
120+
121+
Produced by @ref dynamic_transform. Stored inside
122+
the router's handler table.
123+
*/
104124
template<class F>
105125
struct dynamic_handler
106126
{
107127
F f;
108128

129+
// No extra parameters -- just forward to the callable
130+
template<class First>
131+
route_task
132+
invoke_impl(
133+
route_params& p,
134+
type_list<First> const&) const
135+
{
136+
static_assert(
137+
std::is_convertible_v<route_params&, First>,
138+
"first parameter must accept route_params&");
139+
return f(p);
140+
}
141+
142+
static route_task
143+
make_route_next()
144+
{
145+
co_return route_next;
146+
}
147+
148+
static route_task
149+
wrap_result(route_result r)
150+
{
151+
co_return r;
152+
}
153+
154+
// Extra parameters resolved from route_data
155+
template<class First, class E1, class... Extra>
156+
route_task
157+
invoke_impl(
158+
route_params& p,
159+
type_list<First, E1, Extra...> const&) const
160+
{
161+
static_assert(
162+
std::is_convertible_v<route_params&, First>,
163+
"first parameter must accept route_params&");
164+
static_assert(
165+
are_unique<
166+
find_key_t<E1>,
167+
find_key_t<Extra>...>::value,
168+
"callable has duplicate parameter types");
169+
170+
auto ptrs = std::make_tuple(
171+
p.route_data.template find<find_key_t<E1>>(),
172+
p.route_data.template find<find_key_t<Extra>>()...);
173+
174+
bool all_found = std::apply(
175+
[](auto*... pp)
176+
{
177+
return (... && (pp != nullptr));
178+
}, ptrs);
179+
180+
if(! all_found)
181+
return make_route_next();
182+
183+
using R = std::invoke_result_t<
184+
F const&, route_params&,
185+
find_key_t<E1>&,
186+
find_key_t<Extra>&...>;
187+
if constexpr (std::is_same_v<R, route_task>)
188+
return apply_tuple_deref(
189+
f, p, ptrs, std::index_sequence_for<E1, Extra...>{});
190+
else
191+
return wrap_result(apply_tuple_deref(
192+
f, p, ptrs, std::index_sequence_for<E1, Extra...>{}));
193+
}
194+
109195
route_task
110196
operator()(route_params& p) const
111197
{
112-
co_return dynamic_invoke(
113-
p.route_data, f);
198+
return invoke_impl(p,
199+
typename call_traits<
200+
std::decay_t<F>>::arg_types{});
114201
}
115202
};
116203

117-
/** A handler transform that resolves parameters from route_data.
204+
/** A handler transform that resolves extra parameters from route_data.
118205
119206
When used with @ref router::with_transform, handlers may
120-
declare parameters of arbitrary types. At dispatch time,
121-
each parameter type is looked up in @ref route_params::route_data.
122-
If all parameters are found the handler is invoked; otherwise
123-
@ref route_next is returned.
207+
declare a first parameter of type `route_params&` followed
208+
by additional parameters of arbitrary types. At dispatch time,
209+
each extra parameter type is looked up in
210+
@ref route_params::route_data via @ref polystore::find.
211+
If all extra parameters are found the handler is invoked;
212+
otherwise @ref route_next is returned.
213+
214+
Duplicate extra parameter types (after stripping cv-ref)
215+
produce a compile-time error.
216+
217+
@par Example
218+
@code
219+
router<route_params> base;
220+
auto r = base.with_transform( dynamic_transform{} );
221+
222+
r.get( "/users", [](
223+
route_params& p,
224+
UserService& svc,
225+
Config const& cfg) -> route_result
226+
{
227+
// svc and cfg resolved from p.route_data
228+
return route_done;
229+
});
230+
@endcode
124231
*/
125232
struct dynamic_transform
126233
{

0 commit comments

Comments
 (0)