Skip to content
File

Blob: src/workerd/jsg/meta.h

cpp135 lines
1// Copyright (c) 2017-2022 Cloudflare, Inc.
2// Licensed under the Apache 2.0 license found in the LICENSE file or at:
3// https://opensource.org/licenses/Apache-2.0
4 
5#pragma once
6// INTERNAL IMPLEMENTATION FILE
7 
8#include <v8-function-callback.h>
9 
10#include <kj/tuple.h>
11 
12namespace workerd::jsg {
13 
14class Lock;
15 
16template <typename T>
17struct ArgumentIndexes_;
18template <typename T, typename Ret, typename... Args>
19struct ArgumentIndexes_<Ret (T::*)(Args...)> {
20 using Indexes = kj::_::MakeIndexes<sizeof...(Args)>;
21};
22template <typename T, typename Ret, typename... Args>
23struct ArgumentIndexes_<Ret (T::*)(Lock&, Args...)> {
24 using Indexes = kj::_::MakeIndexes<sizeof...(Args)>;
25};
26template <typename T, typename Ret, typename... Args>
27struct ArgumentIndexes_<Ret (T::*)(const v8::FunctionCallbackInfo<v8::Value>&, Args...)> {
28 using Indexes = kj::_::MakeIndexes<sizeof...(Args)>;
29};
30template <typename T, typename Ret, typename... Args>
31struct ArgumentIndexes_<Ret (T::*)(Args...) const> {
32 using Indexes = kj::_::MakeIndexes<sizeof...(Args)>;
33};
34template <typename T, typename Ret, typename... Args>
35struct ArgumentIndexes_<Ret (T::*)(Lock&, Args...) const> {
36 using Indexes = kj::_::MakeIndexes<sizeof...(Args)>;
37};
38template <typename T, typename Ret, typename... Args>
39struct ArgumentIndexes_<Ret (T::*)(const v8::FunctionCallbackInfo<v8::Value>&, Args...) const> {
40 using Indexes = kj::_::MakeIndexes<sizeof...(Args)>;
41};
42template <typename Ret, typename... Args>
43struct ArgumentIndexes_<Ret(Args...)> {
44 using Indexes = kj::_::MakeIndexes<sizeof...(Args)>;
45};
46template <typename Ret, typename... Args>
47struct ArgumentIndexes_<Ret(Lock&, Args...)> {
48 using Indexes = kj::_::MakeIndexes<sizeof...(Args)>;
49};
50template <typename Ret, typename... Args>
51struct ArgumentIndexes_<Ret(const v8::FunctionCallbackInfo<v8::Value>&, Args...)> {
52 using Indexes = kj::_::MakeIndexes<sizeof...(Args)>;
53};
54template <typename T>
55using ArgumentIndexes = ArgumentIndexes_<T>::Indexes;
56// ArgumentIndexes<SomeMethodType> expands to kj::_::Indexes<0, 1, 2, 3, ..., n-1>, where n is the
57// number of arguments to the method, not counting the magic Lock or FunctionCallbackInfo parameter
58// (if any).
59 
60// =======================================================================================
61// requiredArgumentCount<TypeWrapper, T> — counts leading required JS-visible arguments.
62//
63// Used by resource.h to set the Web IDL .length property on functions.
64//
65// Argument filtering is split across two layers for dependency reasons:
66//
67// 1. StripMagicParam_ (here in meta.h) removes the leading Lock& or
68// FunctionCallbackInfo& parameter. These are C++/V8 plumbing that always
69// appear first and are never JS-visible. meta.h can handle them because
70// it only needs the v8 forward declarations it already includes.
71//
72// 2. RequiredArgCount_ (in type-wrapper.h) skips all "injected" parameter
73// types that don't consume a JS argument. It uses the ValueLessParameter
74// concept to automatically detect types like TypeHandler<T> and
75// InjectConfiguration types (e.g. CompatibilityFlags::Reader), plus
76// isArguments<>() for variadic Arguments<T>. The TypeWrapper template
77// parameter is required because ValueLessParameter checks whether the
78// wrapper has a 3-arg unwrap(js, context, T*) overload for the type.
79 
80// Lightweight type list; kj::Tuple is an alias template and cannot be partially specialized.
81template <typename... Ts>
82struct TypeList {};
83 
84namespace detail {
85 
86// Phase 1: Normalize member-function-pointer or free-function type to Ret(Args...).
87template <typename T>
88struct NormalizeFunc_;
89template <typename C, typename R, typename... A>
90struct NormalizeFunc_<R (C::*)(A...)> {
91 using type = R(A...);
92};
93template <typename C, typename R, typename... A>
94struct NormalizeFunc_<R (C::*)(A...) const> {
95 using type = R(A...);
96};
97template <typename R, typename... A>
98struct NormalizeFunc_<R(A...)> {
99 using type = R(A...);
100};
101 
102// Phase 2: Strip leading Lock& / FunctionCallbackInfo& and yield the JS-visible args.
103// See the comment above for why this is separate from RequiredArgCount_.
104template <typename T>
105struct StripMagicParam_;
106template <typename R, typename... A>
107struct StripMagicParam_<R(A...)> {
108 using Args = TypeList<A...>;
109};
110template <typename R, typename... A>
111struct StripMagicParam_<R(Lock&, A...)> {
112 using Args = TypeList<A...>;
113};
114template <typename R, typename... A>
115struct StripMagicParam_<R(const v8::FunctionCallbackInfo<v8::Value>&, A...)> {
116 using Args = TypeList<A...>;
117};
118 
119template <typename T>
120using MethodArgs = StripMagicParam_<typename NormalizeFunc_<T>::type>;
121 
122// Forward declaration — specialized in type-wrapper.h where ValueLessParameter is visible.
123template <typename TypeWrapper, typename ArgsList>
124struct RequiredArgCount_;
125 
126} // namespace detail
127 
128// Per Web IDL, the .length of a function is the number of leading required arguments.
129// The actual counting logic lives in type-wrapper.h (needs the ValueLessParameter concept).
130template <typename TypeWrapper, typename T>
131inline constexpr int requiredArgumentCount =
132 detail::RequiredArgCount_<TypeWrapper, typename detail::MethodArgs<T>::Args>::value;
133 
134} // namespace workerd::jsg