xref: /aosp_15_r20/external/fbjni/cxx/fbjni/detail/References.h (revision 65c59e023c5336bbd4a23be7af78407e3d80e7e7)
1 /*
2  * Copyright (c) Facebook, Inc. and its affiliates.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 /** @file References.h
18  *
19  * Functionality similar to smart pointers, but for references into the VM. Four
20  * main reference types are provided: local_ref, global_ref, weak_ref, and
21  * alias_ref. All are generic templates that and refer to objects in the jobject
22  * hierarchy. The type of the referred objects are specified using the template
23  * parameter. All reference types except alias_ref own their underlying
24  * reference, just as a std smart pointer owns the underlying raw pointer. In
25  * the context of std smart pointers, these references behave like unique_ptr,
26  * and have basically the same interface. Thus, when the reference is
27  * destructed, the plain JNI reference, i.e. the underlying JNI reference (like
28  * the parameters passed directly to JNI functions), is released. The alias
29  * references provides no ownership and is a simple wrapper for plain JNI
30  * references.
31  *
32  * All but the weak references provides access to the underlying object using
33  * dereferencing, and a get() method. It is also possible to convert these
34  * references to booleans to test for nullity. To access the underlying object
35  * of a weak reference, the reference must either be released, or the weak
36  * reference can be used to create a local or global reference.
37  *
38  * An owning reference is created either by moving the reference from an
39  * existing owned reference, by copying an existing owned reference (which
40  * creates a new underlying reference), by using the default constructor which
41  * initialize the reference to nullptr, or by using a helper function. The
42  * helper function exist in two flavors: make_XXX or adopt_XXX.
43  *
44  * Adopting takes a plain JNI reference and wrap it in an owned reference. It
45  * takes ownership of the plain JNI reference so be sure that no one else owns
46  * the reference when you adopt it, and make sure that you know what kind of
47  * reference it is.
48  *
49  * New owned references can be created from existing plain JNI references, alias
50  * references, local references, and global references (i.e. non-weak
51  * references) using the make_local, make_global, and make_weak functions.
52  *
53  * Alias references can be implicitly initialized using global, local and plain
54  * JNI references using the wrap_alias function. Here, we don't assume ownership
55  * of the passed-in reference, but rather create a separate reference that we do
56  * own, leaving the passed-in reference to its fate.
57  *
58  * Similar rules apply for assignment. An owned reference can be copy or move
59  * assigned using a smart reference of the same type. In the case of copy
60  * assignment a new reference is created. Alias reference can also be assigned
61  * new values, but since they are simple wrappers of plain JNI references there
62  * is no move semantics involved.
63  *
64  * Alias references are special in that they do not own the object and can
65  * therefore safely be converted to and from its corresponding plain JNI
66  * reference. They are useful as parameters of functions that do not affect the
67  * lifetime of a reference. Usage can be compared with using plain JNI pointers
68  * as parameters where a function does not take ownership of the underlying
69  * object.
70  *
71  * The local, global, and alias references makes it possible to access methods
72  * in the underlying objects. A core set of classes are implemented in
73  * CoreClasses.h, and user defined wrappers are supported (see example below).
74  * The wrappers also supports inheritance so a wrapper can inherit from another
75  * wrapper to gain access to its functionality. As an example the jstring
76  * wrapper inherits from the jobject wrapper, so does the jclass wrapper. That
77  * means that you can for example call the toString() method using the jclass
78  * wrapper, or any other class that inherits from the jobject wrapper.
79  *
80  * Note that the wrappers are parameterized on the static type of your (jobject)
81  * pointer, thus if you have a jobject that refers to a Java String you will
82  * need to cast it to jstring to get the jstring wrapper. This also mean that if
83  * you make a down cast that is invalid there will be no one stopping you and
84  * the wrappers currently does not detect this which can cause crashes. Thus,
85  * cast wisely.
86  *
87  * @include WrapperSample.cpp
88  */
89 
90 #pragma once
91 
92 #include <cassert>
93 #include <cstddef>
94 #include <type_traits>
95 
96 #include <jni.h>
97 
98 #include "ReferenceAllocators.h"
99 #include "References-forward.h"
100 #include "TypeTraits.h"
101 
102 namespace facebook {
103 namespace jni {
104 
105 /// Convenience function to wrap an existing local reference
106 template <typename T>
107 local_ref<T> adopt_local(T ref) noexcept;
108 
109 /// Convenience function to wrap an existing global reference
110 template <typename T>
111 global_ref<T> adopt_global(T ref) noexcept;
112 
113 /// Convenience function to wrap an existing weak reference
114 template <typename T>
115 weak_ref<T> adopt_weak_global(T ref) noexcept;
116 
117 /// Swaps two owning references of the same type
118 template <typename T>
119 void swap(weak_ref<T>& a, weak_ref<T>& b) noexcept;
120 
121 /// Swaps two owning references of the same type
122 template <typename T, typename Alloc>
123 void swap(
124     basic_strong_ref<T, Alloc>& a,
125     basic_strong_ref<T, Alloc>& b) noexcept;
126 
127 /**
128  * Retrieve the plain reference from a plain reference.
129  */
130 template <typename T>
131 enable_if_t<IsPlainJniReference<T>(), T> getPlainJniReference(T ref);
132 
133 /**
134  * Retrieve the plain reference from an alias reference.
135  */
136 template <typename T>
137 JniType<T> getPlainJniReference(alias_ref<T> ref);
138 
139 /**
140  * Retrieve the plain JNI reference from any reference owned reference.
141  */
142 template <typename T, typename Alloc>
143 JniType<T> getPlainJniReference(const base_owned_ref<T, Alloc>& ref);
144 
145 class JObject;
146 class JClass;
147 
148 namespace detail {
149 
150 template <typename T>
IsJavaClassType()151 constexpr bool IsJavaClassType() {
152   return std::is_base_of<JObject, T>::value;
153 }
154 
155 template <typename T, typename Enable = void>
156 struct HasJniRefRepr : std::false_type {};
157 
158 template <typename T>
159 struct HasJniRefRepr<
160     T,
161     typename std::enable_if<
162         !std::is_same<typename T::JniRefRepr, void>::value,
163         void>::type> : std::true_type {
164   using type = typename T::JniRefRepr;
165 };
166 
167 template <typename T>
168 struct RefReprType<T*> {
169   static_assert(HasJniRefRepr<T>::value, "Repr type missing JniRefRepr.");
170   using type = typename HasJniRefRepr<T>::type;
171   static_assert(IsJavaClassType<type>(), "Repr type missing JObject base.");
172   static_assert(
173       std::is_same<type, typename RefReprType<type>::type>::value,
174       "RefReprType<T> not idempotent");
175 };
176 
177 template <typename T>
178 struct RefReprType<
179     T,
180     typename std::enable_if<IsJavaClassType<T>(), void>::type> {
181   using type = T;
182   static_assert(IsJavaClassType<type>(), "Repr type missing JObject base.");
183   static_assert(
184       std::is_same<type, typename RefReprType<type>::type>::value,
185       "RefReprType<T> not idempotent");
186 };
187 
188 template <typename T>
189 struct JavaObjectType {
190   using type = typename RefReprType<T>::type::javaobject;
191   static_assert(
192       IsPlainJniReference<type>(),
193       "JavaObjectType<T> not a plain jni reference");
194   static_assert(
195       std::is_same<type, typename JavaObjectType<type>::type>::value,
196       "JavaObjectType<T> not idempotent");
197 };
198 
199 template <typename T>
200 struct JavaObjectType<T*> {
201   using type = T*;
202   static_assert(
203       IsPlainJniReference<type>(),
204       "JavaObjectType<T> not a plain jni reference");
205   static_assert(
206       std::is_same<type, typename JavaObjectType<type>::type>::value,
207       "JavaObjectType<T> not idempotent");
208 };
209 
210 template <typename T>
211 struct PrimitiveOrJavaObjectType<T, enable_if_t<IsJniPrimitive<T>(), void>> {
212   using type = T;
213   static_assert(
214       IsJniPrimitive<type>(),
215       "PrimitiveOrJavaObjectType<T> not a jni primitive");
216   static_assert(
217       std::is_same<type, typename PrimitiveOrJavaObjectType<type>::type>::value,
218       "PrimitiveOrJavaObjectType<T> not idempotent");
219 };
220 
221 template <typename T>
222 struct PrimitiveOrJavaObjectType<
223     T,
224     enable_if_t<IsPlainJniReference<T>(), void>> {
225   using type = T;
226   static_assert(
227       IsPlainJniReference<type>(),
228       "PrimitiveOrJavaObjectType<T> not a plain jni reference");
229   static_assert(
230       std::is_same<type, typename PrimitiveOrJavaObjectType<type>::type>::value,
231       "PrimitiveOrJavaObjectType<T> not idempotent");
232 };
233 
234 template <typename T>
235 struct PrimitiveOrJavaObjectType<T, enable_if_t<IsJavaClassType<T>(), void>> {
236   using type = JniType<T>;
237   static_assert(
238       IsPlainJniReference<type>(),
239       "PrimitiveOrJavaObjectType<T> not a plain jni reference");
240   static_assert(
241       std::is_same<type, typename PrimitiveOrJavaObjectType<type>::type>::value,
242       "PrimitiveOrJavaObjectType<T> not idempotent");
243 };
244 
245 template <typename Repr>
246 struct ReprStorage {
247   explicit ReprStorage(JniType<Repr> obj) noexcept;
248 
249   void set(JniType<Repr> obj) noexcept;
250 
251   Repr& get() noexcept;
252   const Repr& get() const noexcept;
253   JniType<Repr> jobj() const noexcept;
254 
255   void swap(ReprStorage& other) noexcept;
256 
257   ReprStorage() = delete;
258   ReprStorage(const ReprStorage&) = delete;
259   ReprStorage(ReprStorage&&) = delete;
260   ReprStorage& operator=(const ReprStorage&) = delete;
261   ReprStorage& operator=(ReprStorage&&) = delete;
262 
263  private:
264   using Storage = typename std::
265       aligned_storage<sizeof(JObjectBase), alignof(JObjectBase)>::type;
266   Storage storage_;
267 };
268 
269 } // namespace detail
270 
271 /**
272  * Create a new local reference from an existing reference
273  *
274  * @param ref a plain JNI, alias, or strong reference
275  * @return an owned local reference (referring to null if the input does)
276  * @throws std::bad_alloc if the JNI reference could not be created
277  */
278 template <typename T>
279 enable_if_t<IsNonWeakReference<T>(), local_ref<plain_jni_reference_t<T>>>
280 make_local(const T& ref);
281 
282 /**
283  * Create a new global reference from an existing reference
284  *
285  * @param ref a plain JNI, alias, or strong reference
286  * @return an owned global reference (referring to null if the input does)
287  * @throws std::bad_alloc if the JNI reference could not be created
288  */
289 template <typename T>
290 enable_if_t<IsNonWeakReference<T>(), global_ref<plain_jni_reference_t<T>>>
291 make_global(const T& ref);
292 
293 /**
294  * Create a new weak global reference from an existing reference
295  *
296  * @param ref a plain JNI, alias, or strong reference
297  * @return an owned weak global reference (referring to null if the input does)
298  * @throws std::bad_alloc if the returned reference is null
299  */
300 template <typename T>
301 enable_if_t<IsNonWeakReference<T>(), weak_ref<plain_jni_reference_t<T>>>
302 make_weak(const T& ref);
303 
304 /**
305  * Compare two references to see if they refer to the same object
306  */
307 template <typename T1, typename T2>
308 enable_if_t<IsNonWeakReference<T1>() && IsNonWeakReference<T2>(), bool>
309 operator==(const T1& a, const T2& b);
310 
311 /**
312  * Compare two references to see if they don't refer to the same object
313  */
314 template <typename T1, typename T2>
315 enable_if_t<IsNonWeakReference<T1>() && IsNonWeakReference<T2>(), bool>
316 operator!=(const T1& a, const T2& b);
317 
318 /**
319  * Compare references against nullptr
320  */
321 template <typename T1>
322 enable_if_t<IsNonWeakReference<T1>(), bool> operator==(
323     const T1& a,
324     std::nullptr_t);
325 
326 template <typename T1>
327 enable_if_t<IsNonWeakReference<T1>(), bool> operator==(
328     std::nullptr_t,
329     const T1& a);
330 
331 template <typename T1>
332 enable_if_t<IsNonWeakReference<T1>(), bool> operator!=(
333     const T1& a,
334     std::nullptr_t);
335 
336 template <typename T1>
337 enable_if_t<IsNonWeakReference<T1>(), bool> operator!=(
338     std::nullptr_t,
339     const T1& a);
340 
341 template <typename T, typename Alloc>
342 class base_owned_ref {
343  public:
344   using javaobject = JniType<T>;
345 
346   /**
347    * Release the ownership and set the reference to null. Thus no deleter is
348    * invoked.
349    * @return Returns the reference
350    */
351   javaobject release() noexcept;
352 
353   /**
354    * Reset the reference to refer to nullptr.
355    */
356   void reset() noexcept;
357 
358  protected:
359   using Repr = ReprType<T>;
360   detail::ReprStorage<Repr> storage_;
361 
362   javaobject get() const noexcept;
363   void set(javaobject ref) noexcept;
364 
365   /*
366    * Wrap an existing reference and transfers its ownership to the newly created
367    * unique reference. NB! Does not create a new reference
368    */
369   explicit base_owned_ref(javaobject reference) noexcept;
370 
371   /// Create a null reference
372   base_owned_ref() noexcept;
373 
374   /// Create a null reference
375   explicit base_owned_ref(std::nullptr_t) noexcept;
376 
377   /// Copy constructor (note creates a new reference)
378   base_owned_ref(const base_owned_ref& other);
379   template <typename U>
380   base_owned_ref(const base_owned_ref<U, Alloc>& other);
381 
382   /// Transfers ownership of an underlying reference from one unique reference
383   /// to another
384   base_owned_ref(base_owned_ref&& other) noexcept;
385   template <typename U>
386   base_owned_ref(base_owned_ref<U, Alloc>&& other) noexcept;
387 
388   /// The delete the underlying reference if applicable
389   ~base_owned_ref() noexcept;
390 
391   /// Assignment operator (note creates a new reference)
392   base_owned_ref& operator=(const base_owned_ref& other);
393 
394   /// Assignment by moving a reference thus not creating a new reference
395   base_owned_ref& operator=(base_owned_ref&& rhs) noexcept;
396 
397   void reset(javaobject reference) noexcept;
398 
399   friend javaobject jni::getPlainJniReference<>(
400       const base_owned_ref<T, Alloc>& ref);
401 
402   template <typename U, typename UAlloc>
403   friend class base_owned_ref;
404 };
405 
406 /**
407  * A smart reference that owns its underlying JNI reference. The class provides
408  * basic functionality to handle a reference but gives no access to it unless
409  * the reference is released, thus no longer owned. The API is stolen with pride
410  * from unique_ptr and the semantics should be basically the same. This class
411  * should not be used directly, instead use
412  * @ref weak_ref
413  */
414 template <typename T>
415 class weak_ref : public base_owned_ref<T, WeakGlobalReferenceAllocator> {
416  public:
417   using javaobject = JniType<T>;
418 
419   using Allocator = WeakGlobalReferenceAllocator;
420 
421   // This inherits non-default, non-copy, non-move ctors.
422   using base_owned_ref<T, Allocator>::base_owned_ref;
423 
424   /// Create a null reference
425   weak_ref() noexcept : base_owned_ref<T, Allocator>{} {}
426 
427   /// Create a null reference
428   /* implicit */ weak_ref(std::nullptr_t) noexcept
429       : base_owned_ref<T, Allocator>{nullptr} {}
430 
431   /// Copy constructor (note creates a new reference)
432   weak_ref(const weak_ref& other) : base_owned_ref<T, Allocator>{other} {}
433 
434   // This needs to be explicit to change its visibility.
435   template <typename U>
436   weak_ref(const weak_ref<U>& other) : base_owned_ref<T, Allocator>{other} {}
437 
438   /// Transfers ownership of an underlying reference from one unique reference
439   /// to another
440   weak_ref(weak_ref&& other) noexcept
441       : base_owned_ref<T, Allocator>{std::move(other)} {}
442 
443   // Move from ref to compatible type.
444   template <typename U>
445   weak_ref(weak_ref<U>&& other)
446       : base_owned_ref<T, Allocator>{std::move(other)} {}
447 
448   /// Assignment operator (note creates a new reference)
449   weak_ref& operator=(const weak_ref& other);
450 
451   /// Assignment by moving a reference thus not creating a new reference
452   weak_ref& operator=(weak_ref&& rhs) noexcept;
453 
454   // Creates an owned local reference to the referred object or to null if the
455   // object is reclaimed
456   local_ref<T> lockLocal() const;
457 
458   // Creates an owned global reference to the referred object or to null if the
459   // object is reclaimed
460   global_ref<T> lockGlobal() const;
461 
462  private:
463   // get/release/reset on weak_ref are not exposed to users.
464   using base_owned_ref<T, Allocator>::get;
465   using base_owned_ref<T, Allocator>::release;
466   using base_owned_ref<T, Allocator>::reset;
467   /*
468    * Wrap an existing reference and transfers its ownership to the newly created
469    * unique reference. NB! Does not create a new reference
470    */
471   explicit weak_ref(javaobject reference) noexcept
472       : base_owned_ref<T, Allocator>{reference} {}
473 
474   template <typename T2>
475   friend class weak_ref;
476   friend weak_ref<javaobject> adopt_weak_global<javaobject>(
477       javaobject ref) noexcept;
478   friend void swap<T>(weak_ref& a, weak_ref& b) noexcept;
479 };
480 
481 /**
482  * A class representing owned strong references to Java objects. This class
483  * should not be used directly, instead use @ref local_ref, or @ref global_ref.
484  */
485 template <typename T, typename Alloc>
486 class basic_strong_ref : public base_owned_ref<T, Alloc> {
487   using typename base_owned_ref<T, Alloc>::Repr;
488 
489  public:
490   using javaobject = JniType<T>;
491 
492   using Allocator = Alloc;
493 
494   // This inherits non-default, non-copy, non-move ctors.
495   using base_owned_ref<T, Alloc>::base_owned_ref;
496   using base_owned_ref<T, Alloc>::release;
497   using base_owned_ref<T, Alloc>::reset;
498 
499   /// Create a null reference
500   basic_strong_ref() noexcept : base_owned_ref<T, Alloc>{} {}
501 
502   /// Create a null reference
503   /* implicit */ basic_strong_ref(std::nullptr_t) noexcept
504       : base_owned_ref<T, Alloc>{nullptr} {}
505 
506   /// Copy constructor (note creates a new reference)
507   basic_strong_ref(const basic_strong_ref& other)
508       : base_owned_ref<T, Alloc>{other} {}
509 
510   // This needs to be explicit to change its visibility.
511   template <typename U>
512   basic_strong_ref(const basic_strong_ref<U, Alloc>& other)
513       : base_owned_ref<T, Alloc>{other} {}
514 
515   // Move from ref to compatible type.
516   template <typename U>
517   basic_strong_ref(basic_strong_ref<U, Alloc>&& other)
518       : base_owned_ref<T, Alloc>{std::move(other)} {}
519 
520   /// Transfers ownership of an underlying reference from one unique reference
521   /// to another
522   basic_strong_ref(basic_strong_ref&& other) noexcept
523       : base_owned_ref<T, Alloc>{std::move(other)} {}
524 
525   /// Assignment operator (note creates a new reference)
526   basic_strong_ref& operator=(const basic_strong_ref& other);
527 
528   /// Assignment by moving a reference thus not creating a new reference
529   basic_strong_ref& operator=(basic_strong_ref&& rhs) noexcept;
530 
531   /// Get the plain JNI reference
532   using base_owned_ref<T, Allocator>::get;
533 
534   /// Release the ownership of the reference and return the wrapped reference in
535   /// an alias
536   alias_ref<T> releaseAlias() noexcept;
537 
538   /// Checks if the reference points to a non-null object
539   explicit operator bool() const noexcept;
540 
541   /// Access the functionality provided by the object wrappers
542   Repr* operator->() noexcept;
543 
544   /// Access the functionality provided by the object wrappers
545   const Repr* operator->() const noexcept;
546 
547   /// Provide a reference to the underlying wrapper (be sure that it is non-null
548   /// before invoking)
549   Repr& operator*() noexcept;
550 
551   /// Provide a const reference to the underlying wrapper (be sure that it is
552   /// non-null before invoking)
553   const Repr& operator*() const noexcept;
554 
555  private:
556   using base_owned_ref<T, Alloc>::storage_;
557 
558   /*
559    * Wrap an existing reference and transfers its ownership to the newly created
560    * unique reference. NB! Does not create a new reference
561    */
562   explicit basic_strong_ref(javaobject reference) noexcept
563       : base_owned_ref<T, Alloc>{reference} {}
564 
565   friend local_ref<T> adopt_local<T>(T ref) noexcept;
566   friend global_ref<T> adopt_global<T>(T ref) noexcept;
567   friend void swap<T, Alloc>(basic_strong_ref& a, basic_strong_ref& b) noexcept;
568 };
569 
570 template <typename T>
571 enable_if_t<IsPlainJniReference<T>(), alias_ref<T>> wrap_alias(T ref) noexcept;
572 
573 /// Swaps to alias reference of the same type
574 template <typename T>
575 void swap(alias_ref<T>& a, alias_ref<T>& b) noexcept;
576 
577 /**
578  * A non-owning variant of the smart references (a dumb
579  * reference). Use this representation when you don't want to claim
580  * ownership of the underlying reference (compare to using raw
581  * pointers instead of smart pointers.)
582  */
583 template <typename T>
584 class alias_ref {
585   using Repr = ReprType<T>;
586 
587  public:
588   using javaobject = JniType<T>;
589 
590   /// Create a null reference
591   alias_ref() noexcept;
592 
593   /// Create a null reference
594   /* implicit */ alias_ref(std::nullptr_t) noexcept;
595 
596   /// Copy constructor
597   alias_ref(const alias_ref& other) noexcept;
598 
599   /// Wrap an existing plain JNI reference
600   /* implicit */ alias_ref(javaobject ref) noexcept;
601 
602   /// Wrap an existing smart reference of any type convertible to T
603   template <
604       typename TOther,
605       typename = enable_if_t<IsConvertible<JniType<TOther>, javaobject>(), T>>
606   alias_ref(alias_ref<TOther> other) noexcept;
607 
608   /// Wrap an existing alias reference of a type convertible to T
609   template <
610       typename TOther,
611       typename AOther,
612       typename = enable_if_t<IsConvertible<JniType<TOther>, javaobject>(), T>>
613   alias_ref(const basic_strong_ref<TOther, AOther>& other) noexcept;
614 
615   /// Assignment operator
616   alias_ref& operator=(alias_ref other) noexcept;
617 
618   /// Checks if the reference points to a non-null object
619   explicit operator bool() const noexcept;
620 
621   /// Converts back to a plain JNI reference
622   javaobject get() const noexcept;
623 
624   /// Access the functionality provided by the object wrappers
625   Repr* operator->() noexcept;
626 
627   /// Access the functionality provided by the object wrappers
628   const Repr* operator->() const noexcept;
629 
630   /// Provide a guaranteed non-null reference (be sure that it is non-null
631   /// before invoking)
632   Repr& operator*() noexcept;
633 
634   /// Provide a guaranteed non-null reference (be sure that it is non-null
635   /// before invoking)
636   const Repr& operator*() const noexcept;
637 
638  private:
639   void set(javaobject ref) noexcept;
640 
641   detail::ReprStorage<Repr> storage_;
642 
643   friend void swap<T>(alias_ref& a, alias_ref& b) noexcept;
644 };
645 
646 /**
647  * RAII object to create a local JNI frame, using PushLocalFrame/PopLocalFrame.
648  *
649  * This is useful when you have a call which is initiated from C++-land, and
650  * therefore doesn't automatically get a local JNI frame managed for you by the
651  * JNI framework.
652  */
653 class JniLocalScope {
654  public:
655   JniLocalScope(JNIEnv* p_env, jint capacity);
656   ~JniLocalScope();
657 
658  private:
659   JNIEnv* env_;
660   bool hasFrame_;
661 };
662 
663 template <typename T, typename U>
664 enable_if_t<IsPlainJniReference<JniType<T>>(), local_ref<T>> static_ref_cast(
665     const local_ref<U>& ref) noexcept;
666 
667 template <typename T, typename U>
668 enable_if_t<IsPlainJniReference<JniType<T>>(), global_ref<T>> static_ref_cast(
669     const global_ref<U>& ref) noexcept;
670 
671 template <typename T, typename U>
672 enable_if_t<IsPlainJniReference<JniType<T>>(), alias_ref<T>> static_ref_cast(
673     const alias_ref<U>& ref) noexcept;
674 
675 template <typename T, typename RefType>
676 auto dynamic_ref_cast(const RefType& ref)
677     -> enable_if_t<
678         IsPlainJniReference<JniType<T>>(),
679         decltype(static_ref_cast<T>(ref))>;
680 
681 } // namespace jni
682 } // namespace facebook
683 
684 #include "References-inl.h"
685