lime
Lime is a C++ library implementing Open Whisper System Signal protocol
native_method.hpp
Go to the documentation of this file.
1 #pragma once
2 
3 #include <jni/types.hpp>
4 #include <jni/errors.hpp>
5 #include <jni/functions.hpp>
6 #include <jni/tagging.hpp>
7 #include <jni/class.hpp>
8 #include <jni/object.hpp>
9 
10 #include <exception>
11 #include <type_traits>
12 
13 namespace jni
14  {
15  template < class M, class Enable = void >
17 
18  template < class R, class... Args >
19  struct NativeMethodTraits< R (Args...) >
20  {
21  using Type = R (Args...);
22  using ResultType = R;
23  };
24 
25  template < class R, class... Args >
26  struct NativeMethodTraits< R (*)(Args...) >
27  : NativeMethodTraits< R (Args...) > {};
28 
29  template < class T, class R, class... Args >
30  struct NativeMethodTraits< R (T::*)(Args...) const >
31  : NativeMethodTraits< R (Args...) > {};
32 
33  template < class T, class R, class... Args >
34  struct NativeMethodTraits< R (T::*)(Args...) >
35  : NativeMethodTraits< R (Args...) > {};
36 
37  template < class M >
38  struct NativeMethodTraits< M, std::enable_if_t< std::is_class<M>::value > >
39  : NativeMethodTraits< decltype(&M::operator()) > {};
40 
41 
43 
44  template < class M >
45  auto MakeNativeMethod(const char* name, const char* sig, const M& m,
46  std::enable_if_t< std::is_class<M>::value >* = nullptr)
47  {
48  using FunctionType = typename NativeMethodTraits<M>::Type;
49  using ResultType = typename NativeMethodTraits<M>::ResultType;
50 
51  static FunctionType* method = m;
52 
53  auto wrapper = [] (JNIEnv* env, auto... args)
54  {
55  try
56  {
57  return method(env, args...);
58  }
59  catch (...)
60  {
61  ThrowJavaError(*env, std::current_exception());
62  return ResultType();
63  }
64  };
65 
66  return JNINativeMethod< FunctionType > { name, sig, wrapper };
67  }
68 
69 
71 
72  template < class M, M method >
73  auto MakeNativeMethod(const char* name, const char* sig)
74  {
75  using FunctionType = typename NativeMethodTraits<M>::Type;
76  using ResultType = typename NativeMethodTraits<M>::ResultType;
77 
78  auto wrapper = [] (JNIEnv* env, auto... args)
79  {
80  try
81  {
82  return method(env, args...);
83  }
84  catch (...)
85  {
86  ThrowJavaError(*env, std::current_exception());
87  return ResultType();
88  }
89  };
90 
91  return JNINativeMethod< FunctionType > { name, sig, wrapper };
92  }
93 
94 
96 
97  template < class T, T*... >
99 
100  template < class T, class R, class Subject, class... Args >
101  struct NativeMethodMaker< R (T::*)(JNIEnv&, Subject, Args...) const >
102  {
103  template < class M >
104  auto operator()(const char* name, const M& m)
105  {
106  static M method(m);
107 
108  auto wrapper = [] (JNIEnv* env, UntaggedType<Subject> subject, UntaggedType<Args>... args)
109  {
110  return ReleaseUnique(method(*env, AsLvalue(Tag<std::decay_t<Subject>>(*env, *subject)), AsLvalue(Tag<std::decay_t<Args>>(*env, args))...));
111  };
112 
113  return MakeNativeMethod(name, TypeSignature<RemoveUniqueType<R> (std::decay_t<Args>...)>()(), wrapper);
114  }
115  };
116 
117  template < class T, class Subject, class... Args >
118  struct NativeMethodMaker< void (T::*)(JNIEnv&, Subject, Args...) const >
119  {
120  template < class M >
121  auto operator()(const char* name, const M& m)
122  {
123  static M method(m);
124 
125  auto wrapper = [] (JNIEnv* env, UntaggedType<Subject> subject, UntaggedType<Args>... args)
126  {
127  method(*env, AsLvalue(Tag<std::decay_t<Subject>>(*env, *subject)), AsLvalue(Tag<std::decay_t<Args>>(*env, args))...);
128  };
129 
130  return MakeNativeMethod(name, TypeSignature<void (std::decay_t<Args>...)>()(), wrapper);
131  }
132  };
133 
134  template < class M >
135  auto MakeNativeMethod(const char* name, const M& m)
136  {
138  }
139 
140 
142 
143  template < class R, class Subject, class... Args, R (*method)(JNIEnv&, Subject, Args...) >
144  struct NativeMethodMaker< R (JNIEnv&, Subject, Args...), method >
145  {
146  auto operator()(const char* name)
147  {
148  auto wrapper = [] (JNIEnv* env, UntaggedType<Subject> subject, UntaggedType<Args>... args)
149  {
150  return ReleaseUnique(method(*env, AsLvalue(Tag<std::decay_t<Subject>>(*env, *subject)), AsLvalue(Tag<std::decay_t<Args>>(*env, args))...));
151  };
152 
153  return MakeNativeMethod(name, TypeSignature<RemoveUniqueType<R> (std::decay_t<Args>...)>()(), wrapper);
154  }
155  };
156 
157  template < class Subject, class... Args, void (*method)(JNIEnv&, Subject, Args...) >
158  struct NativeMethodMaker< void (JNIEnv&, Subject, Args...), method >
159  {
160  auto operator()(const char* name)
161  {
162  auto wrapper = [] (JNIEnv* env, UntaggedType<Subject> subject, UntaggedType<Args>... args)
163  {
164  method(*env, AsLvalue(Tag<std::decay_t<Subject>>(*env, *subject)), AsLvalue(Tag<std::decay_t<Args>>(*env, args))...);
165  };
166 
167  return MakeNativeMethod(name, TypeSignature<void (std::decay_t<Args>...)>()(), wrapper);
168  }
169  };
170 
171  template < class M, M method >
172  auto MakeNativeMethod(const char* name)
173  {
174  using FunctionType = typename NativeMethodTraits<M>::Type;
176  }
177 
178 
180 
181  template < class L, class >
183 
184  template < class L, class R, class P, class... Args >
185  class NativePeerLambdaMethod< L, R (L::*)(JNIEnv&, P&, Args...) const >
186  {
187  private:
188  const char* name;
189  L lambda;
190 
191  public:
192  NativePeerLambdaMethod(const char* n, const L& l)
193  : name(n), lambda(l)
194  {}
195 
196  template < class Peer, class TagType, class = std::enable_if_t< std::is_same<P, Peer>::value > >
198  {
199  auto wrapper = [field, lambda = lambda] (JNIEnv& env, Object<TagType>& obj, Args... args)
200  {
201  return lambda(env, *reinterpret_cast<P*>(obj.Get(env, field)), args...);
202  };
203 
204  return MakeNativeMethod(name, wrapper);
205  }
206  };
207 
208  template < class L >
209  auto MakeNativePeerMethod(const char* name, const L& lambda,
210  std::enable_if_t< std::is_class<L>::value >* = nullptr)
211  {
213  }
214 
215 
217 
218  template < class M, M* >
220 
221  template < class R, class P, class... Args, R (*method)(JNIEnv&, P&, Args...) >
222  class NativePeerFunctionPointerMethod< R (JNIEnv&, P&, Args...), method >
223  {
224  private:
225  const char* name;
226 
227  public:
229  : name(n)
230  {}
231 
232  template < class Peer, class TagType, class = std::enable_if_t< std::is_same<P, Peer>::value > >
234  {
235  auto wrapper = [field] (JNIEnv& env, Object<TagType>& obj, Args... args)
236  {
237  return method(env, *reinterpret_cast<P*>(obj.Get(env, field)), args...);
238  };
239 
240  return MakeNativeMethod(name, wrapper);
241  }
242  };
243 
244  template < class M, M method >
245  auto MakeNativePeerMethod(const char* name,
246  std::enable_if_t< !std::is_member_function_pointer<M>::value >* = nullptr)
247  {
248  using FunctionType = typename NativeMethodTraits<M>::Type;
250  }
251 
252 
254 
255  template < class M, M >
257 
258  template < class R, class P, class... Args, R (P::*method)(JNIEnv&, Args...) >
259  class NativePeerMemberFunctionMethod< R (P::*)(JNIEnv&, Args...), method >
260  {
261  private:
262  const char* name;
263 
264  public:
266  : name(n)
267  {}
268 
269  template < class Peer, class TagType, class = std::enable_if_t< std::is_same<P, Peer>::value > >
271  {
272  auto wrapper = [field] (JNIEnv& env, Object<TagType>& obj, Args... args)
273  {
274  return (reinterpret_cast<P*>(obj.Get(env, field))->*method)(env, args...);
275  };
276 
277  return MakeNativeMethod(name, wrapper);
278  }
279  };
280 
281  template < class M, M method >
282  auto MakeNativePeerMethod(const char* name,
283  std::enable_if_t< std::is_member_function_pointer<M>::value >* = nullptr)
284  {
286  }
287 
288 
310  template < class Peer, class TagType, class... Methods >
311  void RegisterNativePeer(JNIEnv& env, const Class<TagType>& clazz, const char* fieldName, Methods&&... methods)
312  {
313  static Field<TagType, jni::jlong> field { env, clazz, fieldName };
314  RegisterNatives(env, *clazz, methods.template operator()<Peer>(field)...);
315  }
316 
317  template < class Peer, class TagType, class >
319 
320  template < class Peer, class TagType, class... Args >
321  struct NativePeerHelper< Peer, TagType, std::unique_ptr<Peer> (JNIEnv&, Args...) >
322  {
323  using UniquePeer = std::unique_ptr<Peer>;
324  using Initializer = UniquePeer (JNIEnv&, Args...);
325 
326  auto MakeInitializer(const Field<TagType, jlong>& field, const char* name, Initializer* initializer) const
327  {
328  auto wrapper = [field, initializer] (JNIEnv& e, Object<TagType>& obj, std::decay_t<Args>&... args)
329  {
330  UniquePeer previous(reinterpret_cast<Peer*>(obj.Get(e, field)));
331  UniquePeer instance(initializer(e, args...));
332  obj.Set(e, field, reinterpret_cast<jlong>(instance.get()));
333  instance.release();
334  };
335 
336  return MakeNativeMethod(name, wrapper);
337  }
338 
339  auto MakeFinalizer(const Field<TagType, jlong>& field, const char* name) const
340  {
341  auto wrapper = [field] (JNIEnv& e, Object<TagType>& obj)
342  {
343  UniquePeer instance(reinterpret_cast<Peer*>(obj.Get(e, field)));
344  if (instance) obj.Set(e, field, jlong(0));
345  instance.reset();
346  };
347 
348  return MakeNativeMethod(name, wrapper);
349  }
350  };
351 
352  template < class Peer, class TagType, class Initializer, class... Methods >
353  void RegisterNativePeer(JNIEnv& env, const Class<TagType>& clazz, const char* fieldName,
354  Initializer initialize,
355  const char* initializeMethodName,
356  const char* finalizeMethodName,
357  Methods&&... methods)
358  {
359  static Field<TagType, jlong> field { env, clazz, fieldName };
360 
361  using InitializerMethodType = typename NativeMethodTraits<Initializer>::Type;
363 
364  RegisterNatives(env, *clazz,
365  helper.MakeInitializer(field, initializeMethodName, initialize),
366  helper.MakeFinalizer(field, finalizeMethodName),
367  methods.template operator()<Peer>(field)...);
368  }
369 
370  // Like std::make_unique, but with non-universal reference arguments, so it can be
371  // explicitly specialized (jni::MakePeer<Peer, jni::jboolean, ...>).
372  template < class Peer, class... Args >
373  std::unique_ptr<Peer> MakePeer(jni::JNIEnv& env, Args... args)
374  {
375  return std::make_unique<Peer>(env, args...);
376  }
377  }
decltype(Untag(std::declval< T >())) UntaggedType
Definition: tagging.hpp:130
void RegisterNativePeer(JNIEnv &env, const Class< TagType > &clazz, const char *fieldName, Methods &&... methods)
Definition: native_method.hpp:311
auto operator()(const char *name)
Definition: native_method.hpp:160
auto MakeInitializer(const Field< TagType, jlong > &field, const char *name, Initializer *initializer) const
Definition: native_method.hpp:326
High-level peer, lambda.
Definition: native_method.hpp:182
auto MakeNativePeerMethod(const char *name, const L &lambda, std::enable_if_t< std::is_class< L >::value > *=nullptr)
Definition: native_method.hpp:209
auto ReleaseUnique(T primitive)
Definition: unique.hpp:143
auto operator()(const char *name)
Definition: native_method.hpp:146
auto operator()(const char *name, const M &m)
Definition: native_method.hpp:121
auto operator()(const char *name, const M &m)
Definition: native_method.hpp:104
auto operator()(const Field< TagType, jlong > &field)
Definition: native_method.hpp:197
Definition: errors.hpp:9
std::unique_ptr< Peer > UniquePeer
Definition: native_method.hpp:323
void ThrowJavaError(JNIEnv &env, std::exception_ptr e)
Definition: errors.hpp:101
auto MakeNativeMethod(const char *name, const char *sig, const M &m, std::enable_if_t< std::is_class< M >::value > *=nullptr)
Low-level, lambda.
Definition: native_method.hpp:45
Definition: object.hpp:44
Definition: advanced_ownership.hpp:5
Definition: native_method.hpp:16
UniquePeer(JNIEnv &, Args...) Initializer
Definition: native_method.hpp:324
NativePeerMemberFunctionMethod(const char *n)
Definition: native_method.hpp:265
NativePeerLambdaMethod(const char *n, const L &l)
Definition: native_method.hpp:192
auto MakeFinalizer(const Field< TagType, jlong > &field, const char *name) const
Definition: native_method.hpp:339
High-level peer, function pointer.
Definition: native_method.hpp:219
typename RemoveUnique< T >::Type RemoveUniqueType
Definition: unique.hpp:139
auto operator()(const Field< TagType, jlong > &field)
Definition: native_method.hpp:233
Definition: class.hpp:17
std::unique_ptr< Peer > MakePeer(jni::JNIEnv &env, Args... args)
Definition: native_method.hpp:373
T & AsLvalue(T &&x)
Definition: traits.hpp:33
R ResultType
Definition: native_method.hpp:22
High-level peer, member function pointer.
Definition: native_method.hpp:256
void RegisterNatives(JNIEnv &env, jclass &clazz, const Methods &... methods)
Definition: functions.hpp:573
auto operator()(const Field< TagType, jlong > &field)
Definition: native_method.hpp:270
Definition: class.hpp:11
Definition: types.hpp:64
High-level, lambda.
Definition: native_method.hpp:98
auto Tag(JNIEnv &, T primitive) -> std::enable_if_t< IsPrimitive< T >::value, T >
Definition: tagging.hpp:94
R(Args...) Type
Definition: native_method.hpp:21
Definition: native_method.hpp:318
NativePeerFunctionPointerMethod(const char *n)
Definition: native_method.hpp:228
Definition: tagging.hpp:13