Merge mozilla-central to autoland. a=merge CLOSED TREE
[gecko.git] / js / public / GCVariant.h
blob43610b898b3d941eb2a09358edbbb0e4fa187641
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * vim: set ts=8 sts=2 et sw=2 tw=80:
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #ifndef js_GCVariant_h
8 #define js_GCVariant_h
10 #include "mozilla/Variant.h"
12 #include <type_traits>
14 #include "js/GCPolicyAPI.h"
15 #include "js/RootingAPI.h"
16 #include "js/TracingAPI.h"
18 namespace JS {
20 // These template specializations allow Variant to be used inside GC wrappers.
22 // When matching on GC wrappers around Variants, matching should be done on
23 // the wrapper itself. The matcher class's methods should take Handles or
24 // MutableHandles. For example,
26 // struct MyMatcher
27 // {
28 // using ReturnType = const char*;
29 // ReturnType match(HandleObject o) { return "object"; }
30 // ReturnType match(HandleScript s) { return "script"; }
31 // };
33 // Rooted<Variant<JSObject*, JSScript*>> v(cx, someScript);
34 // MyMatcher mm;
35 // v.match(mm);
37 // If you get compile errors about inability to upcast subclasses (e.g., from
38 // NativeObject* to JSObject*) and are inside js/src, be sure to also include
39 // "gc/Policy.h".
41 namespace detail {
43 template <typename... Ts>
44 struct GCVariantImplementation;
46 // The base case.
47 template <typename T>
48 struct GCVariantImplementation<T> {
49 template <typename ConcreteVariant>
50 static void trace(JSTracer* trc, ConcreteVariant* v, const char* name) {
51 T& thing = v->template as<T>();
52 GCPolicy<T>::trace(trc, &thing, name);
55 template <typename Matcher, typename ConcreteVariant>
56 static typename Matcher::ReturnType match(Matcher& matcher,
57 Handle<ConcreteVariant> v) {
58 const T& thing = v.get().template as<T>();
59 return matcher.match(Handle<T>::fromMarkedLocation(&thing));
62 template <typename Matcher, typename ConcreteVariant>
63 static typename Matcher::ReturnType match(Matcher& matcher,
64 MutableHandle<ConcreteVariant> v) {
65 T& thing = v.get().template as<T>();
66 return matcher.match(MutableHandle<T>::fromMarkedLocation(&thing));
70 // The inductive case.
71 template <typename T, typename... Ts>
72 struct GCVariantImplementation<T, Ts...> {
73 using Next = GCVariantImplementation<Ts...>;
75 template <typename ConcreteVariant>
76 static void trace(JSTracer* trc, ConcreteVariant* v, const char* name) {
77 if (v->template is<T>()) {
78 T& thing = v->template as<T>();
79 GCPolicy<T>::trace(trc, &thing, name);
80 } else {
81 Next::trace(trc, v, name);
85 template <typename Matcher, typename ConcreteVariant>
86 static typename Matcher::ReturnType match(Matcher& matcher,
87 Handle<ConcreteVariant> v) {
88 if (v.get().template is<T>()) {
89 const T& thing = v.get().template as<T>();
90 return matcher.match(Handle<T>::fromMarkedLocation(&thing));
92 return Next::match(matcher, v);
95 template <typename Matcher, typename ConcreteVariant>
96 static typename Matcher::ReturnType match(Matcher& matcher,
97 MutableHandle<ConcreteVariant> v) {
98 if (v.get().template is<T>()) {
99 T& thing = v.get().template as<T>();
100 return matcher.match(MutableHandle<T>::fromMarkedLocation(&thing));
102 return Next::match(matcher, v);
106 } // namespace detail
108 template <typename... Ts>
109 struct GCPolicy<mozilla::Variant<Ts...>> {
110 using Impl = detail::GCVariantImplementation<Ts...>;
112 static void trace(JSTracer* trc, mozilla::Variant<Ts...>* v,
113 const char* name) {
114 Impl::trace(trc, v, name);
117 static bool isValid(const mozilla::Variant<Ts...>& v) {
118 return v.match([](auto& v) {
119 return GCPolicy<std::remove_reference_t<decltype(v)>>::isValid(v);
124 } // namespace JS
126 namespace js {
128 template <typename Wrapper, typename... Ts>
129 class WrappedPtrOperations<mozilla::Variant<Ts...>, Wrapper> {
130 using Impl = JS::detail::GCVariantImplementation<Ts...>;
131 using Variant = mozilla::Variant<Ts...>;
133 const Variant& variant() const {
134 return static_cast<const Wrapper*>(this)->get();
137 public:
138 template <typename T>
139 bool is() const {
140 return variant().template is<T>();
143 template <typename T>
144 JS::Handle<T> as() const {
145 return JS::Handle<T>::fromMarkedLocation(&variant().template as<T>());
148 template <typename Matcher>
149 typename Matcher::ReturnType match(Matcher& matcher) const {
150 return Impl::match(matcher,
151 JS::Handle<Variant>::fromMarkedLocation(&variant()));
155 template <typename Wrapper, typename... Ts>
156 class MutableWrappedPtrOperations<mozilla::Variant<Ts...>, Wrapper>
157 : public WrappedPtrOperations<mozilla::Variant<Ts...>, Wrapper> {
158 using Impl = JS::detail::GCVariantImplementation<Ts...>;
159 using Variant = mozilla::Variant<Ts...>;
161 const Variant& variant() const {
162 return static_cast<const Wrapper*>(this)->get();
164 Variant& variant() { return static_cast<Wrapper*>(this)->get(); }
166 public:
167 template <typename T>
168 JS::MutableHandle<T> as() {
169 return JS::MutableHandle<T>::fromMarkedLocation(
170 &variant().template as<T>());
173 template <typename Matcher>
174 typename Matcher::ReturnType match(Matcher& matcher) {
175 return Impl::match(
176 matcher, JS::MutableHandle<Variant>::fromMarkedLocation(&variant()));
180 } // namespace js
182 #endif // js_GCVariant_h