Skip to content
File

Blob: src/workerd/jsg/rtti.h

cpp976 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// Runtime type system for jsg.
7// Produces capnp description (rtti.capnp) of jsg structs, resources and c++ types of their
8// members.
9// Can be used to generate typescript type, dynamically invoke methods, fuzz, check backward
10// compatibility etc.
11 
12#include <workerd/jsg/jsg.h>
13#include <workerd/jsg/rtti.capnp.h>
14 
15#include <capnp/message.h>
16#include <kj/map.h>
17 
18namespace workerd::jsg::rtti {
19 
20namespace impl {
21 
22// Struct for partial specialization.
23template <typename Configuration, typename T, typename Enable = void>
24struct BuildRtti;
25 
26} // namespace impl
27 
28// User's entry point into rtti.
29// Builder owns capnp builder for all the objects it returns, so usual capnp builder
30// rules apply.
31// The rtti describes object structure and their types.
32// All structure references in rtti are stored by name. The builder maintains a symbol table
33// which can be used to resolve them. It is guaranteed that the table is full enough to
34// interpret all types passed through a given builder.
35template <typename MetaConfiguration>
36class Builder {
37 public:
38 const MetaConfiguration config;
39 
40 Builder(const MetaConfiguration& config): config(config) {}
41 
42 template <typename T>
43 Type::Reader type() {
44 auto type = builder.initRoot<Type>();
45 impl::BuildRtti<MetaConfiguration, T>::build(type, *this);
46 return type;
47 }
48 
49 template <typename T>
50 Structure::Reader structure() {
51 auto name = jsg::fullyQualifiedTypeName(typeid(T));
52 KJ_IF_SOME(builder, symbols.find(name)) {
53 return builder->template getRoot<Structure>();
54 }
55 
56 auto& builder = symbols.insert(kj::str(name), kj::heap<capnp::MallocMessageBuilder>()).value;
57 auto structure = builder->template initRoot<Structure>();
58 impl::BuildRtti<MetaConfiguration, T>::build(structure, *this);
59 return structure;
60 }
61 
62 kj::Maybe<Structure::Reader> structure(kj::StringPtr name) {
63 // lookup structure in the symbol table
64 return symbols.find(name).map([](kj::Own<capnp::MallocMessageBuilder>& builder) {
65 return builder->template getRoot<Structure>();
66 });
67 }
68 
69 private:
70 capnp::MallocMessageBuilder builder;
71 kj::HashMap<kj::String, kj::Own<capnp::MallocMessageBuilder>> symbols;
72};
73 
74namespace impl {
75 
76// Implementation tools
77 
78template <typename Function, typename = void>
79struct FunctionTraits;
80 
81template <typename R, typename... Args>
82struct FunctionTraits<R(Args...)> {
83 using ReturnType = R;
84 using ArgsTuple = std::tuple<Args...>;
85};
86 
87template <typename R, typename... Args>
88struct FunctionTraits<R (*)(Args...)> {
89 using ReturnType = R;
90 using ArgsTuple = std::tuple<Args...>;
91};
92 
93template <typename This, typename R, typename... Args>
94struct FunctionTraits<R (This::*)(Args...)> {
95 using ReturnType = R;
96 using ArgsTuple = std::tuple<Args...>;
97};
98 
99template <typename T>
100struct FunctionTraits<T, std::void_t<decltype(&T::operator())>>
101 : public FunctionTraits<decltype(&T::operator())> {};
102 
103template <typename This, typename R, typename... Args>
104struct FunctionTraits<R (This::*)(Args...) const> {
105 using ReturnType = R;
106 using ArgsTuple = std::tuple<Args...>;
107};
108 
109template <typename Configuration, typename Tuple>
110struct TupleRttiBuilder {
111 static inline void build(capnp::List<Type>::Builder builder, Builder<Configuration>& rtti) {
112 build(std::make_integer_sequence<size_t, std::tuple_size_v<Tuple>>{}, builder, rtti);
113 }
114 
115 private:
116 template <size_t... Indexes>
117 static inline void build(std::integer_sequence<size_t, Indexes...> seq,
118 capnp::List<Type>::Builder builder,
119 Builder<Configuration>& rtti) {
120 ((buildIndex<Indexes>(builder, rtti)), ...);
121 }
122 
123 template <size_t I>
124 static inline void buildIndex(capnp::List<Type>::Builder builder, Builder<Configuration>& rtti) {
125 BuildRtti<Configuration, std::tuple_element_t<I, Tuple>>::build(builder[I], rtti);
126 }
127};
128 
129// Primitives
130 
131template <typename Configuration>
132struct BuildRtti<Configuration, void> {
133 static void build(Type::Builder builder, Builder<Configuration>& rtti) {
134 builder.setVoidt();
135 }
136};
137 
138template <typename Configuration>
139struct BuildRtti<Configuration, bool> {
140 static void build(Type::Builder builder, Builder<Configuration>& rtti) {
141 builder.setBoolt();
142 }
143};
144 
145template <typename Configuration>
146struct BuildRtti<Configuration, jsg::JsBoolean> {
147 static void build(Type::Builder builder, Builder<Configuration>& rtti) {
148 builder.setBoolt();
149 }
150};
151 
152template <typename Configuration>
153struct BuildRtti<Configuration, v8::Value> {
154 static void build(Type::Builder builder, Builder<Configuration>& rtti) {
155 builder.setUnknown();
156 }
157};
158 
159template <typename Configuration>
160struct BuildRtti<Configuration, jsg::JsValue> {
161 static void build(Type::Builder builder, Builder<Configuration>& rtti) {
162 builder.setUnknown();
163 }
164};
165 
166template <typename Configuration>
167struct BuildRtti<Configuration, jsg::JsRegExp> {
168 // This isn't really unknown but we currently do not expose these types at all, so
169 // this is OK for now.
170 static void build(Type::Builder builder, Builder<Configuration>& rtti) {
171 builder.setUnknown();
172 }
173};
174 
175template <typename Configuration>
176struct BuildRtti<Configuration, jsg::JsMap> {
177 // This isn't really unknown but we currently do not expose these types at all, so
178 // this is OK for now.
179 static void build(Type::Builder builder, Builder<Configuration>& rtti) {
180 builder.setUnknown();
181 }
182};
183 
184template <typename Configuration>
185struct BuildRtti<Configuration, jsg::JsSet> {
186 // This isn't really unknown but we currently do not expose these types at all, so
187 // this is OK for now.
188 static void build(Type::Builder builder, Builder<Configuration>& rtti) {
189 builder.setUnknown();
190 }
191};
192 
193template <typename Configuration>
194struct BuildRtti<Configuration, jsg::JsSymbol> {
195 // This isn't really unknown but we currently do not expose these types at all, so
196 // this is OK for now.
197 static void build(Type::Builder builder, Builder<Configuration>& rtti) {
198 builder.setUnknown();
199 }
200};
201 
202// Numbers
203 
204#define DECLARE_NUMBER_TYPE(T) \
205 template <typename Configuration> \
206 struct BuildRtti<Configuration, T> { \
207 static void build(Type::Builder builder, Builder<Configuration>& rtti) { \
208 builder.initNumber().setName(#T); \
209 } \
210 };
211 
212#define FOR_EACH_NUMBER_TYPE(F) \
213 F(char) \
214 F(signed char) \
215 F(unsigned char) \
216 F(short) \
217 F(unsigned short) \
218 F(int) \
219 F(unsigned int) \
220 F(long) \
221 F(unsigned long) \
222 F(long long) \
223 F(unsigned long long) \
224 F(double) \
225 F(jsg::JsNumber) \
226 F(jsg::JsInt32) \
227 F(jsg::JsUint32) \
228 F(jsg::JsBigInt)
229 
230FOR_EACH_NUMBER_TYPE(DECLARE_NUMBER_TYPE)
231 
232#undef FOR_EACH_NUMBER_TYPE
233#undef DECLARE_NUMBER_TYPE
234 
235// Strings
236 
237#define DECLARE_STRING_TYPE(T) \
238 template <typename Configuration> \
239 struct BuildRtti<Configuration, T> { \
240 static void build(Type::Builder builder, Builder<Configuration>& rtti) { \
241 builder.initString().setName(#T); \
242 } \
243 };
244 
245#define FOR_EACH_STRING_TYPE(F) \
246 F(kj::String) \
247 F(kj::StringPtr) \
248 F(v8::String) \
249 F(USVString) \
250 F(DOMString) \
251 F(jsg::JsString)
252 
253FOR_EACH_STRING_TYPE(DECLARE_STRING_TYPE)
254 
255#undef FOR_EACH_STRING_TYPE
256#undef DECLARE_STRING_TYPE
257 
258// Object Types
259 
260template <typename Configuration>
261struct BuildRtti<Configuration, v8::Object> {
262 static void build(Type::Builder builder, Builder<Configuration>& rtti) {
263 builder.setObject();
264 }
265};
266 
267template <typename Configuration>
268struct BuildRtti<Configuration, jsg::Object> {
269 static void build(Type::Builder builder, Builder<Configuration>& rtti) {
270 builder.setObject();
271 }
272};
273 
274template <typename Configuration>
275struct BuildRtti<Configuration, jsg::JsObject> {
276 static void build(Type::Builder builder, Builder<Configuration>& rtti) {
277 builder.setObject();
278 }
279};
280 
281// References
282 
283template <typename Configuration, typename T>
284struct BuildRtti<Configuration, Ref<T>> {
285 static void build(Type::Builder builder, Builder<Configuration>& rtti) {
286 BuildRtti<Configuration, T>::build(builder, rtti);
287 }
288};
289 
290template <typename Configuration, typename T>
291struct BuildRtti<Configuration, V8Ref<T>> {
292 static void build(Type::Builder builder, Builder<Configuration>& rtti) {
293 BuildRtti<Configuration, T>::build(builder, rtti);
294 }
295};
296 
297template <typename Configuration, typename T>
298struct BuildRtti<Configuration, JsRef<T>> {
299 static void build(Type::Builder builder, Builder<Configuration>& rtti) {
300 BuildRtti<Configuration, T>::build(builder, rtti);
301 }
302};
303 
304template <typename Configuration, typename T>
305struct BuildRtti<Configuration, HashableV8Ref<T>> {
306 static void build(Type::Builder builder, Builder<Configuration>& rtti) {
307 BuildRtti<Configuration, T>::build(builder, rtti);
308 }
309};
310 
311template <typename Configuration, typename T>
312struct BuildRtti<Configuration, v8::Local<T>> {
313 static void build(Type::Builder builder, Builder<Configuration>& rtti) {
314 BuildRtti<Configuration, T>::build(builder, rtti);
315 }
316};
317 
318template <typename Configuration, typename T>
319struct BuildRtti<Configuration, v8::Global<T>> {
320 static void build(Type::Builder builder, Builder<Configuration>& rtti) {
321 BuildRtti<Configuration, T>::build(builder, rtti);
322 }
323};
324 
325template <typename Configuration, typename T>
326struct BuildRtti<Configuration, jsg::MemoizedIdentity<T>> {
327 static void build(Type::Builder builder, Builder<Configuration>& rtti) {
328 BuildRtti<Configuration, T>::build(builder, rtti);
329 }
330};
331 
332template <typename Configuration, typename T>
333struct BuildRtti<Configuration, jsg::Identified<T>> {
334 static void build(Type::Builder builder, Builder<Configuration>& rtti) {
335 BuildRtti<Configuration, T>::build(builder, rtti);
336 }
337};
338 
339template <typename Configuration, typename T>
340struct BuildRtti<Configuration, jsg::NonCoercible<T>> {
341 static void build(Type::Builder builder, Builder<Configuration>& rtti) {
342 BuildRtti<Configuration, T>::build(builder, rtti);
343 }
344};
345 
346// Maybe Types
347 
348#define DECLARE_MAYBE_TYPE(T) \
349 template <typename Configuration, typename V> \
350 struct BuildRtti<Configuration, T<V>> { \
351 static void build(Type::Builder builder, Builder<Configuration>& rtti) { \
352 auto maybe = builder.initMaybe(); \
353 BuildRtti<Configuration, V>::build(maybe.initValue(), rtti); \
354 maybe.setName(#T); \
355 } \
356 };
357 
358#define FOR_EACH_MAYBE_TYPE(F) \
359 F(kj::Maybe) \
360 F(jsg::Optional) \
361 F(jsg::LenientOptional)
362 
363FOR_EACH_MAYBE_TYPE(DECLARE_MAYBE_TYPE)
364 
365#undef FOR_EACH_MAYBE_TYPE
366#undef DECLARE_MAYBE_TYPE
367 
368// Array Types
369 
370#define DECLARE_ARRAY_TYPE(T) \
371 template <typename Configuration, typename V> \
372 struct BuildRtti<Configuration, T<V>> { \
373 static void build(Type::Builder builder, Builder<Configuration>& rtti) { \
374 auto array = builder.initArray(); \
375 BuildRtti<Configuration, V>::build(array.initElement(), rtti); \
376 array.setName(#T); \
377 } \
378 };
379 
380#define FOR_EACH_ARRAY_TYPE(F) \
381 F(kj::Array) \
382 F(kj::ArrayPtr) \
383 F(kj::HashSet) \
384 F(jsg::Sequence) \
385 F(jsg::AsyncGenerator) \
386 F(jsg::AsyncGeneratorIgnoringStrings)
387 
388template <typename Configuration>
389struct BuildRtti<Configuration, jsg::JsArray> {
390 static void build(Type::Builder builder, Builder<Configuration>& rtti) {
391 auto array = builder.initArray();
392 BuildRtti<Configuration, JsValue>::build(array.initElement(), rtti);
393 array.setName("jsg::JsArray");
394 }
395};
396 
397FOR_EACH_ARRAY_TYPE(DECLARE_ARRAY_TYPE)
398 
399#undef FOR_EACH_ARRAY_TYPE
400#undef DECLARE_ARRAY_TYPE
401 
402// Misc Generic Types
403 
404template <typename Configuration, typename K, typename V>
405struct BuildRtti<Configuration, jsg::Dict<V, K>> {
406 static void build(Type::Builder builder, Builder<Configuration>& rtti) {
407 auto dict = builder.initDict();
408 BuildRtti<Configuration, K>::build(dict.initKey(), rtti);
409 BuildRtti<Configuration, V>::build(dict.initValue(), rtti);
410 }
411};
412 
413template <typename Configuration, typename... Variants>
414struct BuildRtti<Configuration, kj::OneOf<Variants...>> {
415 using Seq = std::index_sequence_for<Variants...>;
416 using Tuple = std::tuple<Variants...>;
417 
418 template <size_t I>
419 static inline void buildVariant(
420 capnp::List<Type>::Builder builder, Builder<Configuration>& rtti) {
421 BuildRtti<Configuration, std::tuple_element_t<I, Tuple>>::build(builder[I], rtti);
422 }
423 
424 template <size_t... Indexes>
425 static inline void buildVariants(std::integer_sequence<size_t, Indexes...> seq,
426 capnp::List<Type>::Builder builder,
427 Builder<Configuration>& rtti) {
428 ((buildVariant<Indexes>(builder, rtti)), ...);
429 }
430 
431 static void build(Type::Builder builder, Builder<Configuration>& rtti) {
432 auto variants = builder.initOneOf().initVariants(Seq::size());
433 buildVariants(Seq{}, variants, rtti);
434 }
435};
436 
437// Promises
438 
439template <typename Configuration, typename T>
440struct BuildRtti<Configuration, kj::Promise<T>> {
441 static void build(Type::Builder builder, Builder<Configuration>& rtti) {
442 BuildRtti<Configuration, T>::build(builder.initPromise().initValue(), rtti);
443 }
444};
445 
446template <typename Configuration, typename T>
447struct BuildRtti<Configuration, jsg::Promise<T>> {
448 static void build(Type::Builder builder, Builder<Configuration>& rtti) {
449 BuildRtti<Configuration, T>::build(builder.initPromise().initValue(), rtti);
450 }
451};
452 
453template <typename Configuration>
454struct BuildRtti<Configuration, v8::Promise> {
455 static void build(Type::Builder builder, Builder<Configuration>& rtti) {
456 builder.initPromise().initValue().setUnknown();
457 }
458};
459 
460// Builtins
461 
462#define DECLARE_BUILTIN_TYPE(T, V) \
463 template <typename Configuration> \
464 struct BuildRtti<Configuration, T> { \
465 static void build(Type::Builder builder, Builder<Configuration>& rtti) { \
466 builder.initBuiltin().setType(V); \
467 } \
468 };
469 
470#define FOR_EACH_BUILTIN_TYPE(F, ...) \
471 F(jsg::JsUint8Array, BuiltinType::Type::V8_UINT8_ARRAY) \
472 F(jsg::JsArrayBuffer, BuiltinType::Type::V8_ARRAY_BUFFER) \
473 F(jsg::JsArrayBufferView, BuiltinType::Type::V8_ARRAY_BUFFER_VIEW) \
474 F(jsg::JsBufferSource, BuiltinType::Type::JSG_BUFFER_SOURCE) \
475 F(jsg::BufferSource, BuiltinType::Type::JSG_BUFFER_SOURCE) \
476 F(kj::Date, BuiltinType::Type::KJ_DATE) \
477 F(v8::ArrayBufferView, BuiltinType::Type::V8_ARRAY_BUFFER_VIEW) \
478 F(v8::ArrayBuffer, BuiltinType::Type::V8_ARRAY_BUFFER) \
479 F(v8::Function, BuiltinType::Type::V8_FUNCTION) \
480 F(v8::Uint8Array, BuiltinType::Type::V8_UINT8_ARRAY) \
481 F(jsg::JsDate, BuiltinType::Type::KJ_DATE)
482 
483FOR_EACH_BUILTIN_TYPE(DECLARE_BUILTIN_TYPE)
484 
485#undef FOR_EACH_BUILTIN_TYPE
486#undef DECLARE_BUILTIN_TYPE
487 
488// Jsg implementation types
489 
490#define DECLARE_JSG_IMPL_TYPE(T, V) \
491 template <typename Configuration> \
492 struct BuildRtti<Configuration, T> { \
493 static void build(Type::Builder builder, Builder<Configuration>& rtti) { \
494 builder.initJsgImpl().setType(V); \
495 } \
496 };
497 
498#define FOR_EACH_JSG_IMPL_TYPE(F, ...) \
499 F(jsg::Lock, JsgImplType::Type::JSG_LOCK) \
500 F(jsg::Name, JsgImplType::Type::JSG_NAME) \
501 F(jsg::SelfRef, JsgImplType::Type::JSG_SELF_REF) \
502 F(jsg::Unimplemented, JsgImplType::Type::JSG_UNIMPLEMENTED) \
503 F(v8::Isolate*, JsgImplType::Type::V8_ISOLATE) \
504 F(v8::FunctionCallbackInfo<v8::Value>, JsgImplType::Type::V8_FUNCTION_CALLBACK_INFO) \
505 F(v8::PropertyCallbackInfo<v8::Value>, JsgImplType::Type::V8_PROPERTY_CALLBACK_INFO)
506 
507FOR_EACH_JSG_IMPL_TYPE(DECLARE_JSG_IMPL_TYPE)
508 
509#undef FOR_EACH_JSG_IMPL_TYPE
510#undef DECLARE_JSG_IMPL_TYPE
511 
512template <typename Configuration, typename T>
513struct BuildRtti<Configuration, Arguments<T>> {
514 static void build(Type::Builder builder, Builder<Configuration>& rtti) {
515 // TODO(someday): Create a representation of Arguments<T> that actually encodes the type T.
516 builder.initJsgImpl().setType(JsgImplType::Type::JSG_VARARGS);
517 }
518};
519 
520template <typename Configuration>
521struct BuildRtti<Configuration, Configuration> {
522 static void build(Type::Builder builder, Builder<Configuration>& rtti) {
523 builder.initJsgImpl().setType(JsgImplType::Type::CONFIGURATION);
524 }
525};
526 
527template <typename Configuration, typename T>
528struct BuildRtti<Configuration, jsg::TypeHandler<T>> {
529 static void build(Type::Builder builder, Builder<Configuration>& rtti) {
530 builder.initJsgImpl().setType(JsgImplType::Type::JSG_TYPE_HANDLER);
531 }
532};
533 
534// Functions
535 
536template <typename Configuration, typename Fn>
537struct BuildRtti<Configuration, jsg::Function<Fn>> {
538 static void build(Type::Builder builder, Builder<Configuration>& rtti) {
539 auto fn = builder.initFunction();
540 using Traits = FunctionTraits<Fn>;
541 BuildRtti<Configuration, typename Traits::ReturnType>::build(fn.initReturnType(), rtti);
542 using Args = Traits::ArgsTuple;
543 TupleRttiBuilder<Configuration, Args>::build(fn.initArgs(std::tuple_size_v<Args>), rtti);
544 }
545};
546 
547// C++ modifiers
548 
549template <typename Configuration, typename T>
550struct BuildRtti<Configuration, const T> {
551 static void build(Type::Builder builder, Builder<Configuration>& rtti) {
552 BuildRtti<Configuration, T>::build(builder, rtti);
553 }
554};
555 
556template <typename Configuration, typename T>
557struct BuildRtti<Configuration, T&> {
558 static void build(Type::Builder builder, Builder<Configuration>& rtti) {
559 BuildRtti<Configuration, T>::build(builder, rtti);
560 }
561};
562 
563template <typename Configuration, typename T>
564struct BuildRtti<Configuration, T&&> {
565 static void build(Type::Builder builder, Builder<Configuration>& rtti) {
566 BuildRtti<Configuration, T>::build(builder, rtti);
567 }
568};
569 
570template <typename Configuration, typename T>
571struct BuildRtti<Configuration, const T&> {
572 static void build(Type::Builder builder, Builder<Configuration>& rtti) {
573 BuildRtti<Configuration, T>::build(builder, rtti);
574 }
575};
576 
577// Structs
578 
579// count all members in the structure
580struct MemberCounter {
581 template <typename Type, typename GetNamedMethod, GetNamedMethod getNamedMethod>
582 inline void registerWildcardProperty() { /* not a member */ }
583 
584 template <const char* name, auto Method>
585 inline void registerMethod() {
586 ++members;
587 }
588 
589 template <typename Method, Method method>
590 inline void registerCallable() { /* not a member */ }
591 
592 template <typename Type>
593 inline void registerInherit() { /* inherit is not a member */ }
594 
595 template <const char* name>
596 inline void registerInheritIntrinsic(v8::Intrinsic intrinsic) { /* inherit is not a member */ }
597 
598 template <const char* name, typename Method, Method method>
599 inline void registerIterable() { /* not a member */ }
600 
601 template <const char* name, typename Method, Method method>
602 inline void registerAsyncIterable() { /* not a member */ }
603 
604 template <const char* name, typename Method, Method method>
605 inline void registerDispose() { /* not a member */ }
606 
607 template <const char* name, typename Method, Method method>
608 inline void registerAsyncDispose() { /* not a member */ }
609 
610 template <typename Type, const char* name>
611 inline void registerNestedType() {
612 ++members;
613 }
614 
615 template <typename Property, auto property>
616 inline void registerStructProperty(const char* name) {
617 ++members;
618 }
619 
620 template <const char* name, typename Getter, Getter getter>
621 inline void registerReadonlyPrototypeProperty() {
622 ++members;
623 }
624 
625 template <const char* name, typename Getter, Getter getter, typename Setter, Setter setter>
626 inline void registerPrototypeProperty() {
627 ++members;
628 }
629 
630 template <const char* name, typename Getter, Getter getter>
631 inline void registerReadonlyInstanceProperty() {
632 ++members;
633 }
634 
635 template <typename T>
636 inline void registerReadonlyInstanceProperty(kj::StringPtr, T value) {
637 ++members;
638 }
639 
640 template <const char* name, typename Getter, Getter getter, typename Setter, Setter setter>
641 inline void registerInstanceProperty() {
642 ++members;
643 }
644 
645 template <const char* name, typename Getter, Getter getter, bool readOnly>
646 inline void registerLazyInstanceProperty() {
647 ++members;
648 }
649 
650 template <const char* name, typename Getter, Getter getter>
651 inline void registerInspectProperty() { /* not included */ }
652 
653 template <const char* name, typename T>
654 inline void registerStaticConstant(T value) {
655 ++members;
656 }
657 
658 template <const char* name, typename Getter, Getter getter>
659 inline void registerStaticProperty() {
660 ++members;
661 }
662 
663 template <const char* name, typename Method, Method method>
664 inline void registerStaticMethod() {
665 ++members;
666 }
667 
668 inline void registerTypeScriptRoot() { /* not a member */ }
669 
670 template <const char* tsOverride>
671 inline void registerTypeScriptOverride() { /* not a member */ }
672 
673 template <const char* tsDefine>
674 inline void registerTypeScriptDefine() { /* not a member */ }
675 
676 inline void registerJsBundle(Bundle::Reader bundle) {
677 modules += bundle.getModules().size();
678 }
679 
680 size_t members = 0;
681 size_t modules = 0;
682};
683 
684template <typename Self, typename Configuration>
685struct MembersBuilder {
686 Structure::Builder structure;
687 capnp::List<Member>::Builder members;
688 capnp::List<Module>::Builder modules;
689 Builder<Configuration>& rtti;
690 uint memberIndex = 0;
691 uint moduleIndex = 0;
692 
693 MembersBuilder(Structure::Builder structure,
694 capnp::List<Member>::Builder members,
695 capnp::List<Module>::Builder modules,
696 Builder<Configuration>& rtti)
697 : structure(structure),
698 members(members),
699 modules(modules),
700 rtti(rtti) {}
701 
702 template <typename Type>
703 inline void registerInherit() {
704 BuildRtti<Configuration, Type>::build(structure.initExtends(), rtti);
705 }
706 
707 template <const char* name>
708 inline void registerInheritIntrinsic(v8::Intrinsic intrinsic) {
709 structure.initExtends().initIntrinsic().setName(name);
710 }
711 
712 template <typename Type, const char* name>
713 inline void registerNestedType() {
714 auto nested = members[memberIndex++].initNested();
715 nested.setName(name);
716 BuildRtti<Configuration, Type>::build(nested.initStructure(), rtti);
717 }
718 
719 template <const char* name, typename Getter, Getter getter, typename Setter, Setter setter>
720 inline void registerInstanceProperty() {
721 auto prop = members[memberIndex++].initProperty();
722 prop.setName(name);
723 prop.setGetterFastApiCompatible(isFastApiCompatible<Getter>);
724 prop.setSetterFastApiCompatible(isFastApiCompatible<Setter>);
725 using GetterTraits = FunctionTraits<Getter>;
726 BuildRtti<Configuration, typename GetterTraits::ReturnType>::build(prop.initType(), rtti);
727 }
728 
729 template <const char* name, typename Getter, Getter getter>
730 inline void registerReadonlyInstanceProperty() {
731 auto prop = members[memberIndex++].initProperty();
732 prop.setName(name);
733 prop.setReadonly(true);
734 prop.setGetterFastApiCompatible(isFastApiCompatible<Getter>);
735 using GetterTraits = FunctionTraits<Getter>;
736 BuildRtti<Configuration, typename GetterTraits::ReturnType>::build(prop.initType(), rtti);
737 }
738 
739 template <typename T>
740 inline void registerReadonlyInstanceProperty(kj::StringPtr name, T value) {
741 auto prop = members[memberIndex++].initProperty();
742 prop.setName(name);
743 prop.setReadonly(true);
744 BuildRtti<Configuration, T>::build(prop.initType(), rtti);
745 }
746 
747 template <const char* name, typename Getter, Getter getter, bool readOnly>
748 inline void registerLazyInstanceProperty() {
749 auto prop = members[memberIndex++].initProperty();
750 prop.setName(name);
751 prop.setReadonly(readOnly);
752 prop.setLazy(true);
753 using GetterTraits = FunctionTraits<Getter>;
754 BuildRtti<Configuration, typename GetterTraits::ReturnType>::build(prop.initType(), rtti);
755 }
756 
757 template <const char* name, typename Getter, Getter getter, typename Setter, Setter setter>
758 inline void registerPrototypeProperty() {
759 auto prop = members[memberIndex++].initProperty();
760 prop.setName(name);
761 prop.setPrototype(true);
762 prop.setGetterFastApiCompatible(isFastApiCompatible<Getter>);
763 prop.setSetterFastApiCompatible(isFastApiCompatible<Setter>);
764 using GetterTraits = FunctionTraits<Getter>;
765 BuildRtti<Configuration, typename GetterTraits::ReturnType>::build(prop.initType(), rtti);
766 }
767 
768 template <const char* name, typename Getter, Getter getter>
769 inline void registerReadonlyPrototypeProperty() {
770 auto prop = members[memberIndex++].initProperty();
771 prop.setName(name);
772 prop.setPrototype(true);
773 prop.setReadonly(true);
774 using GetterTraits = FunctionTraits<Getter>;
775 BuildRtti<Configuration, typename GetterTraits::ReturnType>::build(prop.initType(), rtti);
776 }
777 
778 template <const char* name, typename Getter, Getter getter>
779 inline void registerInspectProperty() {}
780 
781 template <const char* name, typename T>
782 inline void registerStaticConstant(T value) {
783 auto constant = members[memberIndex++].initConstant();
784 constant.setName(name);
785 constant.setValue(value);
786 // BuildRtti<Configuration, T>::build(constant.initType());
787 }
788 
789 template <const char* name, typename Getter, Getter getter>
790 inline void registerStaticProperty() {
791 auto prop = members[memberIndex++].initProperty();
792 prop.setName(name);
793 prop.setReadonly(true);
794 prop.setGetterFastApiCompatible(isFastApiCompatible<Getter>);
795 using GetterTraits = FunctionTraits<Getter>;
796 BuildRtti<Configuration, typename GetterTraits::ReturnType>::build(prop.initType(), rtti);
797 }
798 
799 template <typename Property, Property Self::*property>
800 void registerStructProperty(const char* name) {
801 auto prop = members[memberIndex++].initProperty();
802 prop.setName(name);
803 BuildRtti<Configuration, Property>::build(prop.initType(), rtti);
804 }
805 
806 template <const char* name, auto Method>
807 inline void registerMethod() {
808 auto method = members[memberIndex++].initMethod();
809 
810 method.setName(name);
811 method.setFastApiCompatible(isFastApiCompatible<decltype(Method)>);
812 
813 using Traits = FunctionTraits<decltype(Method)>;
814 BuildRtti<Configuration, typename Traits::ReturnType>::build(method.initReturnType(), rtti);
815 using Args = Traits::ArgsTuple;
816 TupleRttiBuilder<Configuration, Args>::build(method.initArgs(std::tuple_size_v<Args>), rtti);
817 }
818 
819 template <typename Method, Method method>
820 inline void registerCallable() {
821 auto func = structure.initCallable();
822 
823 using Traits = FunctionTraits<Method>;
824 BuildRtti<Configuration, typename Traits::ReturnType>::build(func.initReturnType(), rtti);
825 using Args = Traits::ArgsTuple;
826 TupleRttiBuilder<Configuration, Args>::build(func.initArgs(std::tuple_size_v<Args>), rtti);
827 }
828 
829 template <const char* name, typename Method, Method>
830 inline void registerStaticMethod() {
831 auto method = members[memberIndex++].initMethod();
832 
833 method.setName(name);
834 method.setStatic(true);
835 method.setFastApiCompatible(isFastApiCompatible<Method>);
836 
837 using Traits = FunctionTraits<Method>;
838 BuildRtti<Configuration, typename Traits::ReturnType>::build(method.initReturnType(), rtti);
839 using Args = Traits::ArgsTuple;
840 TupleRttiBuilder<Configuration, Args>::build(method.initArgs(std::tuple_size_v<Args>), rtti);
841 }
842 
843 template <const char* name, typename Method, Method>
844 inline void registerIterable() {
845 structure.setIterable(true);
846 
847 auto method = structure.initIterator();
848 method.setName(name);
849 using Traits = FunctionTraits<Method>;
850 BuildRtti<Configuration, typename Traits::ReturnType>::build(method.initReturnType(), rtti);
851 using Args = Traits::ArgsTuple;
852 TupleRttiBuilder<Configuration, Args>::build(method.initArgs(std::tuple_size_v<Args>), rtti);
853 }
854 
855 template <const char* name, typename Method, Method>
856 inline void registerAsyncIterable() {
857 structure.setAsyncIterable(true);
858 
859 auto method = structure.initAsyncIterator();
860 method.setName(name);
861 using Traits = FunctionTraits<Method>;
862 BuildRtti<Configuration, typename Traits::ReturnType>::build(method.initReturnType(), rtti);
863 using Args = Traits::ArgsTuple;
864 TupleRttiBuilder<Configuration, Args>::build(method.initArgs(std::tuple_size_v<Args>), rtti);
865 }
866 
867 template <const char* name, typename Method, Method>
868 inline void registerDispose() {
869 structure.setDisposable(true);
870 
871 auto method = structure.initDispose();
872 method.setName(name);
873 using Traits = FunctionTraits<Method>;
874 BuildRtti<Configuration, typename Traits::ReturnType>::build(method.initReturnType(), rtti);
875 using Args = Traits::ArgsTuple;
876 TupleRttiBuilder<Configuration, Args>::build(method.initArgs(std::tuple_size_v<Args>), rtti);
877 }
878 
879 template <const char* name, typename Method, Method>
880 inline void registerAsyncDispose() {
881 structure.setAsyncDisposable(true);
882 
883 auto method = structure.initAsyncDispose();
884 method.setName(name);
885 using Traits = FunctionTraits<Method>;
886 BuildRtti<Configuration, typename Traits::ReturnType>::build(method.initReturnType(), rtti);
887 using Args = Traits::ArgsTuple;
888 TupleRttiBuilder<Configuration, Args>::build(method.initArgs(std::tuple_size_v<Args>), rtti);
889 }
890 
891 inline void registerTypeScriptRoot() {
892 structure.setTsRoot(true);
893 }
894 
895 template <const char* tsOverride>
896 inline void registerTypeScriptOverride() {
897 structure.setTsOverride(tsOverride);
898 }
899 
900 template <const char* tsDefine>
901 inline void registerTypeScriptDefine() {
902 structure.setTsDefine(tsDefine);
903 }
904 
905 inline void registerJsBundle(Bundle::Reader bundle) {
906 for (auto module: bundle.getModules()) {
907 auto m = modules[moduleIndex++];
908 m.setSpecifier(module.getName());
909 m.setTsDeclarations(module.getTsDeclaration());
910 }
911 }
912 
913 template <typename Type, typename GetNamedMethod, GetNamedMethod getNamedMethod>
914 inline void registerWildcardProperty() {
915 // Nothing to do in this case.
916 }
917};
918 
919// Concept: true when T has registerMembers() function generated by JSG_RESOURCE/JSG_STRUCT
920template <typename T>
921concept HasRegisterMembers = requires { T::template registerMembers<MemberCounter, T>; };
922 
923// Concept: true when T has constructor() function
924template <typename T>
925concept HasConstructor = requires { T::constructor; };
926 
927template <typename Configuration, typename T>
928 requires HasRegisterMembers<T>
929struct BuildRtti<Configuration, T> {
930 static void build(Type::Builder builder, Builder<Configuration>& rtti) {
931 auto structure = builder.initStructure();
932 structure.setName(jsg::typeName(typeid(T)));
933 structure.setFullyQualifiedName(jsg::fullyQualifiedTypeName(typeid(T)));
934 rtti.template structure<T>();
935 }
936 
937 static void build(Structure::Builder builder, Builder<Configuration>& rtti) {
938 builder.setName(jsg::typeName(typeid(T)));
939 builder.setFullyQualifiedName(jsg::fullyQualifiedTypeName(typeid(T)));
940 
941 MemberCounter counter;
942 if constexpr (isDetected<GetConfiguration, T>()) {
943 T::template registerMembers<decltype(counter), T>(counter, rtti.config);
944 } else {
945 T::template registerMembers<decltype(counter), T>(counter);
946 }
947 auto membersCount = counter.members;
948 
949 if constexpr (HasConstructor<T>) {
950 membersCount++;
951 }
952 
953 auto members = builder.initMembers(membersCount);
954 auto modules = counter.modules > 0 ? builder.initBuiltinModules(counter.modules)
955 : capnp::List<Module>::Builder();
956 MembersBuilder<T, Configuration> membersBuilder(builder, members, modules, rtti);
957 if constexpr (isDetected<GetConfiguration, T>()) {
958 T::template registerMembers<decltype(membersBuilder), T>(membersBuilder, rtti.config);
959 } else {
960 T::template registerMembers<decltype(membersBuilder), T>(membersBuilder);
961 }
962 
963 if constexpr (HasConstructor<T>) {
964 auto constructor = members[membersBuilder.memberIndex++].initConstructor();
965 using Traits = FunctionTraits<decltype(T::constructor)>;
966 using Args = Traits::ArgsTuple;
967 TupleRttiBuilder<Configuration, Args>::build(
968 constructor.initArgs(std::tuple_size_v<Args>), rtti);
969 }
970 }
971};
972 
973} // namespace impl
974 
975} // namespace workerd::jsg::rtti