@@ -152,38 +152,91 @@ class CompletionCallbackHandle {
152152 void (*user_data_delete_fn_)(void *);
153153};
154154
155+ template <typename T>
156+ struct TypedCompletionCallbackData {
157+ typename Future<T>::TypedCompletionCallback callback;
158+ void * user_data;
159+ };
160+
161+ template <typename T>
162+ inline void TypedCompletionCallbackTrampoline (const FutureBase& future,
163+ void * data_ptr) {
164+ auto * data = static_cast <TypedCompletionCallbackData<T>*>(data_ptr);
165+ if (data != nullptr && data->callback != nullptr ) {
166+ data->callback (static_cast <const Future<T>&>(future), data->user_data );
167+ }
168+ }
169+
170+ template <typename T>
171+ inline void DeleteTypedCompletionCallbackData (void * data_ptr) {
172+ delete static_cast <TypedCompletionCallbackData<T>*>(data_ptr);
173+ }
174+
155175} // namespace detail
156176
157177template <class T >
158178void Future<T>::OnCompletion(TypedCompletionCallback callback,
159179 void * user_data) const {
160- FutureBase::OnCompletion (reinterpret_cast <CompletionCallback>(callback),
161- user_data);
180+ MutexLock lock (mutex_);
181+ if (api_ != nullptr ) {
182+ if (callback == nullptr ) {
183+ api_->AddCompletionCallback (
184+ handle_, [](const FutureBase&, void *) {}, nullptr , nullptr ,
185+ /* clear_existing_callbacks=*/ true );
186+ } else {
187+ auto * data =
188+ new detail::TypedCompletionCallbackData<T>{callback, user_data};
189+ api_->AddCompletionCallback (
190+ handle_, detail::TypedCompletionCallbackTrampoline<T>, data,
191+ detail::DeleteTypedCompletionCallbackData<T>,
192+ /* clear_existing_callbacks=*/ true );
193+ }
194+ }
162195}
163196
164197#if defined(FIREBASE_USE_STD_FUNCTION)
165198template <class ResultType >
166199inline void Future<ResultType>::OnCompletion(
167200 std::function<void (const Future<ResultType>&)> callback) const {
168- FutureBase::OnCompletion (
169- *reinterpret_cast <std::function<void (const FutureBase&)>*>(&callback));
201+ if (!callback) {
202+ FutureBase::OnCompletion ([](const FutureBase&, void *) {}, nullptr );
203+ } else {
204+ FutureBase::OnCompletion ([callback](const FutureBase& future) {
205+ callback (static_cast <const Future<ResultType>&>(future));
206+ });
207+ }
170208}
171209#endif // defined(FIREBASE_USE_STD_FUNCTION)
172210
173211#if defined(INTERNAL_EXPERIMENTAL)
174212template <class T >
175213FutureBase::CompletionCallbackHandle Future<T>::AddOnCompletion(
176214 TypedCompletionCallback callback, void * user_data) const {
177- return FutureBase::AddOnCompletion (
178- reinterpret_cast <CompletionCallback>(callback), user_data);
215+ MutexLock lock (mutex_);
216+ if (api_ != nullptr ) {
217+ if (callback == nullptr ) {
218+ return CompletionCallbackHandle ();
219+ }
220+ auto * data =
221+ new detail::TypedCompletionCallbackData<T>{callback, user_data};
222+ return api_->AddCompletionCallback (
223+ handle_, detail::TypedCompletionCallbackTrampoline<T>, data,
224+ detail::DeleteTypedCompletionCallbackData<T>,
225+ /* clear_existing_callbacks=*/ false );
226+ }
227+ return CompletionCallbackHandle ();
179228}
180229
181230#if defined(FIREBASE_USE_STD_FUNCTION)
182231template <class ResultType >
183232inline FutureBase::CompletionCallbackHandle Future<ResultType>::AddOnCompletion(
184233 std::function<void (const Future<ResultType>&)> callback) const {
185- return FutureBase::AddOnCompletion (
186- *reinterpret_cast <std::function<void (const FutureBase&)>*>(&callback));
234+ if (!callback) {
235+ return CompletionCallbackHandle ();
236+ }
237+ return FutureBase::AddOnCompletion ([callback](const FutureBase& future) {
238+ callback (static_cast <const Future<ResultType>&>(future));
239+ });
187240}
188241#endif // defined(FIREBASE_USE_STD_FUNCTION)
189242
0 commit comments