xref: /aosp_15_r20/external/fbjni/cxx/fbjni/detail/MetaConvert.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 #pragma once
18 
19 #include <jni.h>
20 
21 #include "Common.h"
22 #include "References.h"
23 
24 namespace facebook {
25 namespace jni {
26 
27 namespace detail {
28 
29 // In order to avoid potentially filling the jni locals table,
30 // temporary objects (right now, this is just jstrings) need to be
31 // released. This is done by returning a holder which autoconverts to
32 // jstring.
33 template <typename T>
callToJni(T && t)34 inline T callToJni(T&& t) {
35   return t;
36 }
37 
38 template <typename T>
callToJni(local_ref<T> && sref)39 inline JniType<T> callToJni(local_ref<T>&& sref) {
40   return sref.get();
41 }
42 
43 template <typename T>
toPlainJniReference(T obj)44 enable_if_t<IsPlainJniReference<T>(), T> toPlainJniReference(T obj) {
45   return obj;
46 }
47 
48 template <typename T>
toPlainJniReference(T repr)49 enable_if_t<IsJavaClassType<T>(), JniType<T>> toPlainJniReference(T repr) {
50   return ReprAccess<T>::get(repr);
51 }
52 
53 // Normally, pass through types unmolested.
54 template <typename T, typename Enabled = void>
55 struct Convert {
56   typedef T jniType;
fromJniConvert57   static jniType fromJni(jniType t) {
58     return t;
59   }
toJniRetConvert60   static jniType toJniRet(jniType t) {
61     return t;
62   }
toCallConvert63   static jniType toCall(jniType t) {
64     return t;
65   }
66 };
67 
68 // This is needed for return conversion
69 template <>
70 struct Convert<void> {
71   typedef void jniType;
72 };
73 
74 // jboolean is an unsigned char, not a bool. Allow it to work either way.
75 template <>
76 struct Convert<bool> {
77   typedef jboolean jniType;
78   static bool fromJni(jniType t) {
79     return t;
80   }
81   static jniType toJniRet(bool t) {
82     return t;
83   }
84   static jniType toCall(bool t) {
85     return t;
86   }
87 };
88 
89 // Sometimes (64-bit Android) jlong is "long long", but int64_t is "long".
90 // Allow int64_t to work as jlong.
91 template <typename T>
92 struct Convert<
93     T,
94     typename std::enable_if<
95         (std::is_same<T, long long>::value ||
96          std::is_same<T, int64_t>::value) &&
97         !std::is_same<T, jlong>::value>::type> {
98   typedef jlong jniType;
99   static T fromJni(jniType t) {
100     return t;
101   }
102   static jniType toJniRet(T t) {
103     return t;
104   }
105   static jniType toCall(T t) {
106     return t;
107   }
108 };
109 
110 // convert to alias_ref<T> from T
111 template <typename T>
112 struct Convert<alias_ref<T>> {
113   typedef JniType<T> jniType;
114   static alias_ref<jniType> fromJni(jniType t) {
115     return wrap_alias(t);
116   }
117   static jniType toJniRet(alias_ref<jniType> t) {
118     return t.get();
119   }
120   static jniType toCall(const alias_ref<jniType>& t) {
121     return t.get();
122   }
123 };
124 
125 // convert return from local_ref<T>
126 template <typename T>
127 struct Convert<local_ref<T>> {
128   typedef JniType<T> jniType;
129   // No automatic synthesis of local_ref
130   static jniType toJniRet(local_ref<jniType> t) {
131     return t.release();
132   }
133   static jniType toCall(const local_ref<jniType>& t) {
134     return t.get();
135   }
136 };
137 
138 // convert return from global_ref<T>
139 template <typename T>
140 struct Convert<global_ref<T>> {
141   typedef JniType<T> jniType;
142   // No automatic synthesis of global_ref
143   static jniType toJniRet(global_ref<jniType>&& t) {
144     // If this gets called, ownership the global_ref was passed in here.  (It's
145     // probably a copy of a persistent global_ref made when a function was
146     // declared to return a global_ref, but it could moved out or otherwise not
147     // referenced elsewhere.  Doesn't matter.)  Either way, the only safe way
148     // to return it is to make a local_ref, release it, and return the
149     // underlying local jobject.
150     auto ret = make_local(t);
151     return ret.release();
152   }
153   static jniType toJniRet(const global_ref<jniType>& t) {
154     // If this gets called, the function was declared to return const&.  We
155     // have a ref to a global_ref whose lifetime will exceed this call, so we
156     // can just get the underlying jobject and return it to java without
157     // needing to make a local_ref.
158     return t.get();
159   }
160   static jniType toCall(const global_ref<jniType>& t) {
161     return t.get();
162   }
163 };
164 
165 template <typename T>
166 struct jni_sig_from_cxx_t;
167 template <typename R, typename... Args>
168 struct jni_sig_from_cxx_t<R(Args...)> {
169   using JniRet = typename Convert<typename std::decay<R>::type>::jniType;
170   using JniSig =
171       JniRet(typename Convert<typename std::decay<Args>::type>::jniType...);
172 };
173 
174 template <typename T>
175 using jni_sig_from_cxx = typename jni_sig_from_cxx_t<T>::JniSig;
176 
177 } // namespace detail
178 
179 template <typename R, typename... Args>
180 struct jmethod_traits_from_cxx<R(Args...)>
181     : jmethod_traits<detail::jni_sig_from_cxx<R(Args...)>> {};
182 
183 } // namespace jni
184 } // namespace facebook
185