Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mapsme/omim.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorArsentiy Milchakov <milcars@mapswithme.com>2017-08-14 18:03:27 +0300
committerRoman Kuznetsov <r.kuznetsow@gmail.com>2017-08-14 18:40:03 +0300
commit1b29af7619a71e2800a5fba73659be9f48071b7b (patch)
tree42ffa991b674ce249c909fa9b26f28e09355acb9
parent9b6ad225e90471db31d4ed27ecc52f8d34d29db5 (diff)
[partners_api][android] safe callbacksbeta-963
-rw-r--r--android/jni/com/mapswithme/maps/Sponsored.cpp37
-rw-r--r--android/jni/com/mapswithme/maps/taxi/TaxiManager.cpp92
-rw-r--r--android/jni/com/mapswithme/maps/viator/Viator.cpp42
-rw-r--r--base/base.pro1
-rw-r--r--base/waiter.hpp79
-rw-r--r--partners_api/booking_api.cpp3
-rw-r--r--partners_api/booking_api.hpp6
-rw-r--r--partners_api/cian_api.cpp4
-rw-r--r--partners_api/cian_api.hpp7
-rw-r--r--partners_api/partners_api.pro2
-rw-r--r--partners_api/partners_api_tests/async_gui_thread.hpp24
-rw-r--r--partners_api/partners_api_tests/booking_tests.cpp52
-rw-r--r--partners_api/partners_api_tests/cian_tests.cpp14
-rw-r--r--partners_api/partners_api_tests/partners_api_tests.pro3
-rw-r--r--partners_api/partners_api_tests/taxi_engine_tests.cpp22
-rw-r--r--partners_api/partners_api_tests/uber_tests.cpp12
-rw-r--r--partners_api/partners_api_tests/viator_tests.cpp18
-rw-r--r--partners_api/partners_api_tests/yandex_tests.cpp12
-rw-r--r--partners_api/taxi_engine.hpp7
-rw-r--r--partners_api/viator_api.hpp4
-rw-r--r--platform/platform.pro1
-rw-r--r--platform/safe_callback.hpp41
-rw-r--r--testing/testing.hpp3
-rw-r--r--testing/testingmain.cpp16
-rw-r--r--xcode/base/base.xcodeproj/project.pbxproj4
-rw-r--r--xcode/partners_api/partners_api.xcodeproj/project.pbxproj4
-rw-r--r--xcode/platform/platform.xcodeproj/project.pbxproj4
27 files changed, 361 insertions, 153 deletions
diff --git a/android/jni/com/mapswithme/maps/Sponsored.cpp b/android/jni/com/mapswithme/maps/Sponsored.cpp
index 11f379845f..be6a66261a 100644
--- a/android/jni/com/mapswithme/maps/Sponsored.cpp
+++ b/android/jni/com/mapswithme/maps/Sponsored.cpp
@@ -137,9 +137,9 @@ JNIEXPORT void JNICALL Java_com_mapswithme_maps_widget_placepage_Sponsored_nativ
std::string const code = jni::ToNativeString(env, currencyCode);
- g_framework->RequestBookingMinPrice(env, policy, hotelId, code,
- [](std::string const & hotelId, std::string const & price, std::string const & currency) {
- GetPlatform().RunOnGuiThread([hotelId, price, currency]() {
+ g_framework->RequestBookingMinPrice(
+ env, policy, hotelId, code,
+ [](std::string const hotelId, std::string const price, std::string const currency) {
if (g_lastRequestedHotelId != hotelId)
return;
@@ -147,7 +147,6 @@ JNIEXPORT void JNICALL Java_com_mapswithme_maps_widget_placepage_Sponsored_nativ
env->CallStaticVoidMethod(g_sponsoredClass, g_priceCallback, jni::ToJavaString(env, hotelId),
jni::ToJavaString(env, price), jni::ToJavaString(env, currency));
});
- });
}
// static void nativeRequestInfo(String id, String locale);
@@ -164,22 +163,20 @@ JNIEXPORT void JNICALL Java_com_mapswithme_maps_widget_placepage_Sponsored_nativ
if (code.size() > 2) // 2 - number of characters in country code
code.resize(2);
- g_framework->RequestBookingInfo(env, policy, hotelId, code, [hotelId](HotelInfo const & hotelInfo) {
- GetPlatform().RunOnGuiThread([hotelId, hotelInfo]() {
- if (g_lastRequestedHotelId != hotelId)
- return;
- JNIEnv * env = jni::GetEnv();
-
- auto description = jni::ToJavaString(env, hotelInfo.m_description);
- auto photos = ToPhotosArray(env, hotelInfo.m_photos);
- auto facilities = ToFacilitiesArray(env, hotelInfo.m_facilities);
- auto reviews = ToReviewsArray(env, hotelInfo.m_reviews);
- auto nearby = env->NewObjectArray(0, g_nearbyObjectClass, 0);
- jlong reviewsCount = static_cast<jlong>(hotelInfo.m_scoreCount);
- env->CallStaticVoidMethod(g_sponsoredClass, g_infoCallback, jni::ToJavaString(env, hotelId),
- env->NewObject(g_hotelInfoClass, g_hotelInfoConstructor, description,
- photos, facilities, reviews, nearby, reviewsCount));
- });
+ g_framework->RequestBookingInfo(env, policy, hotelId, code, [hotelId](HotelInfo const hotelInfo) {
+ if (g_lastRequestedHotelId != hotelId)
+ return;
+ JNIEnv * env = jni::GetEnv();
+
+ auto description = jni::ToJavaString(env, hotelInfo.m_description);
+ auto photos = ToPhotosArray(env, hotelInfo.m_photos);
+ auto facilities = ToFacilitiesArray(env, hotelInfo.m_facilities);
+ auto reviews = ToReviewsArray(env, hotelInfo.m_reviews);
+ auto nearby = env->NewObjectArray(0, g_nearbyObjectClass, 0);
+ jlong reviewsCount = static_cast<jlong>(hotelInfo.m_scoreCount);
+ env->CallStaticVoidMethod(g_sponsoredClass, g_infoCallback, jni::ToJavaString(env, hotelId),
+ env->NewObject(g_hotelInfoClass, g_hotelInfoConstructor, description,
+ photos, facilities, reviews, nearby, reviewsCount));
});
}
} // extern "C"
diff --git a/android/jni/com/mapswithme/maps/taxi/TaxiManager.cpp b/android/jni/com/mapswithme/maps/taxi/TaxiManager.cpp
index 60ec177ca5..f132469d90 100644
--- a/android/jni/com/mapswithme/maps/taxi/TaxiManager.cpp
+++ b/android/jni/com/mapswithme/maps/taxi/TaxiManager.cpp
@@ -53,65 +53,61 @@ void PrepareClassRefs(JNIEnv * env)
void OnTaxiInfoReceived(taxi::ProvidersContainer const & providers, uint64_t const requestId)
{
- GetPlatform().RunOnGuiThread([=]() {
- if (g_lastRequestId != requestId)
- return;
-
- JNIEnv * env = jni::GetEnv();
-
- auto const productBuilder = [](JNIEnv * env, taxi::Product const & item)
- {
- jni::TScopedLocalRef jProductId(env, jni::ToJavaString(env, item.m_productId));
- jni::TScopedLocalRef jName(env, jni::ToJavaString(env, item.m_name));
- jni::TScopedLocalRef jTime(env, jni::ToJavaString(env, item.m_time));
- jni::TScopedLocalRef jPrice(env, jni::ToJavaString(env, item.m_price));
- jni::TScopedLocalRef jCurrency(env, jni::ToJavaString(env, item.m_currency));
- return env->NewObject(g_productClass, g_productConstructor, jProductId.get(), jName.get(),
- jTime.get(), jPrice.get(), jCurrency.get());
- };
-
- auto const providerBuilder = [productBuilder](JNIEnv * env, taxi::Provider const & item)
- {
- return env->NewObject(g_taxiInfoClass, g_taxiInfoConstructor, item.GetType(),
- jni::ToJavaArray(env, g_productClass, item.GetProducts(), productBuilder));
- };
-
- jni::TScopedLocalObjectArrayRef jProviders(env, jni::ToJavaArray(env, g_taxiInfoClass, providers,
- providerBuilder));
-
- jobject const taxiManagerInstance = env->GetStaticObjectField(g_taxiManagerClass,
- g_taxiManagerInstanceField);
- env->CallVoidMethod(taxiManagerInstance, g_taxiInfoCallbackMethod, jProviders.get());
-
- jni::HandleJavaException(env);
- });
+ if (g_lastRequestId != requestId)
+ return;
+
+ JNIEnv * env = jni::GetEnv();
+
+ auto const productBuilder = [](JNIEnv * env, taxi::Product const & item)
+ {
+ jni::TScopedLocalRef jProductId(env, jni::ToJavaString(env, item.m_productId));
+ jni::TScopedLocalRef jName(env, jni::ToJavaString(env, item.m_name));
+ jni::TScopedLocalRef jTime(env, jni::ToJavaString(env, item.m_time));
+ jni::TScopedLocalRef jPrice(env, jni::ToJavaString(env, item.m_price));
+ jni::TScopedLocalRef jCurrency(env, jni::ToJavaString(env, item.m_currency));
+ return env->NewObject(g_productClass, g_productConstructor, jProductId.get(), jName.get(),
+ jTime.get(), jPrice.get(), jCurrency.get());
+ };
+
+ auto const providerBuilder = [productBuilder](JNIEnv * env, taxi::Provider const & item)
+ {
+ return env->NewObject(g_taxiInfoClass, g_taxiInfoConstructor, item.GetType(),
+ jni::ToJavaArray(env, g_productClass, item.GetProducts(), productBuilder));
+ };
+
+ jni::TScopedLocalObjectArrayRef jProviders(env, jni::ToJavaArray(env, g_taxiInfoClass, providers,
+ providerBuilder));
+
+ jobject const taxiManagerInstance = env->GetStaticObjectField(g_taxiManagerClass,
+ g_taxiManagerInstanceField);
+ env->CallVoidMethod(taxiManagerInstance, g_taxiInfoCallbackMethod, jProviders.get());
+
+ jni::HandleJavaException(env);
}
void OnTaxiError(taxi::ErrorsContainer const & errors, uint64_t const requestId)
{
- GetPlatform().RunOnGuiThread([=]() {
- if (g_lastRequestId != requestId)
- return;
+ if (g_lastRequestId != requestId)
+ return;
- JNIEnv * env = jni::GetEnv();
+ JNIEnv * env = jni::GetEnv();
- jobject const taxiManagerInstance = env->GetStaticObjectField(g_taxiManagerClass,
- g_taxiManagerInstanceField);
+ jobject const taxiManagerInstance = env->GetStaticObjectField(g_taxiManagerClass,
+ g_taxiManagerInstanceField);
- auto const errorBuilder = [](JNIEnv * env, taxi::ProviderError const & error)
- {
- jni::TScopedLocalRef jErrorCode(env, jni::ToJavaString(env, taxi::DebugPrint(error.m_code)));
- return env->NewObject(g_taxiInfoErrorClass, g_taxiInfoErrorConstructor, error.m_type,
- jErrorCode.get());
- };
+ auto const errorBuilder = [](JNIEnv * env, taxi::ProviderError const & error)
+ {
+ jni::TScopedLocalRef jErrorCode(env, jni::ToJavaString(env, taxi::DebugPrint(error.m_code)));
+ return env->NewObject(g_taxiInfoErrorClass, g_taxiInfoErrorConstructor, error.m_type,
+ jErrorCode.get());
+ };
- jni::TScopedLocalObjectArrayRef jErrors(env, jni::ToJavaArray(env, g_taxiInfoErrorClass, errors, errorBuilder));
+ jni::TScopedLocalObjectArrayRef jErrors(env, jni::ToJavaArray(env, g_taxiInfoErrorClass, errors, errorBuilder));
- env->CallVoidMethod(taxiManagerInstance, g_taxiErrorCallbackMethod, jErrors.get());
+ env->CallVoidMethod(taxiManagerInstance, g_taxiErrorCallbackMethod, jErrors.get());
- jni::HandleJavaException(env);
- });
+ jni::HandleJavaException(env);
}
} // namespace
diff --git a/android/jni/com/mapswithme/maps/viator/Viator.cpp b/android/jni/com/mapswithme/maps/viator/Viator.cpp
index 26537c88c3..58c216dad6 100644
--- a/android/jni/com/mapswithme/maps/viator/Viator.cpp
+++ b/android/jni/com/mapswithme/maps/viator/Viator.cpp
@@ -30,31 +30,29 @@ void PrepareClassRefs(JNIEnv * env)
void OnViatorProductsReceived(std::string const & destId,
std::vector<viator::Product> const & products)
{
- GetPlatform().RunOnGuiThread([=]() {
- if (g_lastDestId != destId)
- return;
+ if (g_lastDestId != destId)
+ return;
- JNIEnv * env = jni::GetEnv();
+ JNIEnv * env = jni::GetEnv();
- jni::TScopedLocalRef jDestId(env, jni::ToJavaString(env, destId));
- jni::TScopedLocalRef jProducts(
- env,
- jni::ToJavaArray(env, g_viatorProductClass, products, [](JNIEnv * env,
- viator::Product const & item) {
- jni::TScopedLocalRef jTitle(env, jni::ToJavaString(env, item.m_title));
- jni::TScopedLocalRef jDuration(env, jni::ToJavaString(env, item.m_duration));
- jni::TScopedLocalRef jPriceFormatted(env, jni::ToJavaString(env, item.m_priceFormatted));
- jni::TScopedLocalRef jCurrency(env, jni::ToJavaString(env, item.m_currency));
- jni::TScopedLocalRef jPhotoUrl(env, jni::ToJavaString(env, item.m_photoUrl));
- jni::TScopedLocalRef jPageUrl(env, jni::ToJavaString(env, item.m_pageUrl));
- return env->NewObject(g_viatorProductClass, g_viatorProductConstructor, jTitle.get(),
- item.m_rating, item.m_reviewCount, jDuration.get(), item.m_price,
- jPriceFormatted.get(), jCurrency.get(), jPhotoUrl.get(),
- jPageUrl.get());
- }));
+ jni::TScopedLocalRef jDestId(env, jni::ToJavaString(env, destId));
+ jni::TScopedLocalRef jProducts(
+ env,
+ jni::ToJavaArray(env, g_viatorProductClass, products, [](JNIEnv * env,
+ viator::Product const & item) {
+ jni::TScopedLocalRef jTitle(env, jni::ToJavaString(env, item.m_title));
+ jni::TScopedLocalRef jDuration(env, jni::ToJavaString(env, item.m_duration));
+ jni::TScopedLocalRef jPriceFormatted(env, jni::ToJavaString(env, item.m_priceFormatted));
+ jni::TScopedLocalRef jCurrency(env, jni::ToJavaString(env, item.m_currency));
+ jni::TScopedLocalRef jPhotoUrl(env, jni::ToJavaString(env, item.m_photoUrl));
+ jni::TScopedLocalRef jPageUrl(env, jni::ToJavaString(env, item.m_pageUrl));
+ return env->NewObject(g_viatorProductClass, g_viatorProductConstructor, jTitle.get(),
+ item.m_rating, item.m_reviewCount, jDuration.get(), item.m_price,
+ jPriceFormatted.get(), jCurrency.get(), jPhotoUrl.get(),
+ jPageUrl.get());
+ }));
- env->CallStaticVoidMethod(g_viatorClass, g_viatorCallback, jDestId.get(), jProducts.get());
- });
+ env->CallStaticVoidMethod(g_viatorClass, g_viatorCallback, jDestId.get(), jProducts.get());
}
} // namespace
diff --git a/base/base.pro b/base/base.pro
index 30ba11ba74..5eece9bb1f 100644
--- a/base/base.pro
+++ b/base/base.pro
@@ -99,4 +99,5 @@ HEADERS += \
timegm.hpp \
timer.hpp \
uni_string_dfa.hpp \
+ waiter.hpp \
worker_thread.hpp \
diff --git a/base/waiter.hpp b/base/waiter.hpp
new file mode 100644
index 0000000000..038fe5cf53
--- /dev/null
+++ b/base/waiter.hpp
@@ -0,0 +1,79 @@
+#pragma once
+
+#include <chrono>
+#include <condition_variable>
+#include <mutex>
+
+namespace base
+{
+// Class for multithreaded interruptable waiting.
+class Waiter
+{
+public:
+ enum class Result
+ {
+ PreviouslyNotified,
+ Timeout,
+ NoTimeout
+ };
+
+ void Wait()
+ {
+ std::unique_lock<std::mutex> lock(m_mutex);
+
+ if (m_notified)
+ return;
+
+ m_event.wait(lock, [this]() { return m_notified; });
+ }
+
+ template <typename Rep, typename Period>
+ Result Wait(std::chrono::duration<Rep, Period> const & waitDuration)
+ {
+ std::unique_lock<std::mutex> lock(m_mutex);
+
+ if (m_notified)
+ return Result::PreviouslyNotified;
+
+ auto const result = m_event.wait_for(lock, waitDuration, [this]() { return m_notified; });
+
+ return result ? Result::NoTimeout : Result::Timeout;
+ }
+
+ void Notify()
+ {
+ SetNotified(true);
+
+ m_event.notify_all();
+ }
+
+ void Reset()
+ {
+ SetNotified(false);
+ }
+
+private:
+ void SetNotified(bool notified)
+ {
+ std::lock_guard<std::mutex> lock(m_mutex);
+ m_notified = notified;
+ }
+
+ bool m_notified = false;
+ std::mutex m_mutex;
+ std::condition_variable m_event;
+};
+
+inline std::string DebugPrint(Waiter::Result result)
+{
+ switch (result)
+ {
+ case Waiter::Result::PreviouslyNotified: return "PreviouslyNotified";
+ case Waiter::Result::NoTimeout: return "NoTimeout";
+ case Waiter::Result::Timeout: return "Timeout";
+ default: ASSERT(false, ("Unsupported value"));
+ }
+
+ return {};
+}
+} // namespace base
diff --git a/partners_api/booking_api.cpp b/partners_api/booking_api.cpp
index 4d2447c223..2b1cb97bb3 100644
--- a/partners_api/booking_api.cpp
+++ b/partners_api/booking_api.cpp
@@ -308,8 +308,7 @@ string Api::GetSearchUrl(string const & city, string const & name) const
return resultStream.str();
}
-void Api::GetMinPrice(string const & hotelId, string const & currency,
- GetMinPriceCallback const & fn)
+void Api::GetMinPrice(string const & hotelId, string const & currency, GetMinPriceCallback const & fn)
{
GetPlatform().RunOnNetworkThread([hotelId, currency, fn]()
{
diff --git a/partners_api/booking_api.hpp b/partners_api/booking_api.hpp
index 4d4c2481d8..c81acd611c 100644
--- a/partners_api/booking_api.hpp
+++ b/partners_api/booking_api.hpp
@@ -1,5 +1,7 @@
#pragma once
+#include "platform/safe_callback.hpp"
+
#include "std/chrono.hpp"
#include "std/function.hpp"
#include "std/shared_ptr.hpp"
@@ -52,8 +54,8 @@ public:
static bool GetExtendedInfo(string const & hotelId, string const & lang, string & result);
};
-using GetMinPriceCallback = function<void(string const & hotelId, string const & price, string const & currency)>;
-using GetHotelInfoCallback = function<void(HotelInfo const & hotelInfo)>;
+using GetMinPriceCallback = platform::SafeCallback<void(string const & hotelId, string const & price, string const & currency)>;
+using GetHotelInfoCallback = platform::SafeCallback<void(HotelInfo const & hotelInfo)>;
class Api
{
diff --git a/partners_api/cian_api.cpp b/partners_api/cian_api.cpp
index 65121de75d..6bc4ff6600 100644
--- a/partners_api/cian_api.cpp
+++ b/partners_api/cian_api.cpp
@@ -131,7 +131,7 @@ uint64_t Api::GetRentNearby(ms::LatLon const & latlon, RentNearbyCallback const
if (!rawResult)
{
auto & code = rawResult.m_errorCode;
- GetPlatform().RunOnGuiThread([onError, code, reqId]() { onError(code, reqId); });
+ onError(code, reqId);
return;
}
@@ -144,7 +144,7 @@ uint64_t Api::GetRentNearby(ms::LatLon const & latlon, RentNearbyCallback const
LOG(LERROR, (e.Msg()));
result.clear();
}
- GetPlatform().RunOnGuiThread([onSuccess, result, reqId]() { onSuccess(result, reqId); });
+ onSuccess(result, reqId);
});
return reqId;
diff --git a/partners_api/cian_api.hpp b/partners_api/cian_api.hpp
index f60ab3452d..e98fd31b2c 100644
--- a/partners_api/cian_api.hpp
+++ b/partners_api/cian_api.hpp
@@ -5,6 +5,8 @@
#include "geometry/latlon.hpp"
#include "geometry/rect2d.hpp"
+#include "platform/safe_callback.hpp"
+
#include "base/worker_thread.hpp"
#include <cstdint>
@@ -51,10 +53,11 @@ struct RentPlace
class Api
{
public:
+
using RentNearbyCallback =
- std::function<void(std::vector<RentPlace> const & places, uint64_t const requestId)>;
+ platform::SafeCallback<void(std::vector<RentPlace> const & places, uint64_t const requestId)>;
- using ErrorCallback = std::function<void(int httpCode, uint64_t const requestId)>;
+ using ErrorCallback = platform::SafeCallback<void(int httpCode, uint64_t const requestId)>;
explicit Api(std::string const & baseUrl = kBaseUrl);
diff --git a/partners_api/partners_api.pro b/partners_api/partners_api.pro
index 4b16e21884..f1b7d6f081 100644
--- a/partners_api/partners_api.pro
+++ b/partners_api/partners_api.pro
@@ -41,5 +41,5 @@ HEADERS += \
taxi_provider.hpp \
uber_api.hpp \
utils.hpp \
- viator_api.cpp \
+ viator_api.hpp \
yandex_api.hpp \
diff --git a/partners_api/partners_api_tests/async_gui_thread.hpp b/partners_api/partners_api_tests/async_gui_thread.hpp
new file mode 100644
index 0000000000..df2b0ad78a
--- /dev/null
+++ b/partners_api/partners_api_tests/async_gui_thread.hpp
@@ -0,0 +1,24 @@
+#pragma once
+
+#include "platform/gui_thread.hpp"
+#include "platform/platform.hpp"
+
+#include "base/stl_add.hpp"
+#include "base/worker_thread.hpp"
+
+namespace partners_api
+{
+class AsyncGuiThread
+{
+public:
+ AsyncGuiThread()
+ {
+ GetPlatform().SetGuiThread(my::make_unique<base::WorkerThread>());
+ }
+
+ virtual ~AsyncGuiThread()
+ {
+ GetPlatform().SetGuiThread(my::make_unique<platform::GuiThread>());
+ }
+};
+} // namespace partners_api
diff --git a/partners_api/partners_api_tests/booking_tests.cpp b/partners_api/partners_api_tests/booking_tests.cpp
index 4ca08535f8..43755bc77f 100644
--- a/partners_api/partners_api_tests/booking_tests.cpp
+++ b/partners_api/partners_api_tests/booking_tests.cpp
@@ -1,9 +1,13 @@
#include "testing/testing.hpp"
+#include "partners_api/partners_api_tests/async_gui_thread.hpp"
+
#include "partners_api/booking_api.hpp"
#include "base/scope_guard.hpp"
+using namespace partners_api;
+
namespace
{
UNIT_TEST(Booking_GetHotelAvailability)
@@ -22,7 +26,7 @@ UNIT_TEST(Booking_GetExtendedInfo)
TEST(!result.empty(), ());
}
-UNIT_TEST(Booking_GetMinPrice)
+UNIT_CLASS_TEST(AsyncGuiThread, Booking_GetMinPrice)
{
booking::SetBookingUrlForTesting("http://localhost:34568/booking/min_price");
MY_SCOPE_GUARD(cleanup, []() { booking::SetBookingUrlForTesting(""); });
@@ -38,9 +42,9 @@ UNIT_TEST(Booking_GetMinPrice)
hotelId = id;
price = val;
currency = curr;
- testing::StopEventLoop();
+ testing::Notify();
});
- testing::RunEventLoop();
+ testing::Wait();
TEST_EQUAL(hotelId, kHotelId, ());
TEST(!price.empty(), ());
@@ -57,9 +61,9 @@ UNIT_TEST(Booking_GetMinPrice)
hotelId = id;
price = val;
currency = curr;
- testing::StopEventLoop();
+ testing::Notify();
});
- testing::RunEventLoop();
+ testing::Wait();
TEST_EQUAL(hotelId, kHotelId, ());
TEST(!price.empty(), ());
@@ -76,9 +80,9 @@ UNIT_TEST(Booking_GetMinPrice)
hotelId = id;
price = val;
currency = curr;
- testing::StopEventLoop();
+ testing::Notify();
});
- testing::RunEventLoop();
+ testing::Wait();
TEST_EQUAL(hotelId, kHotelId, ());
TEST(!price.empty(), ());
@@ -87,23 +91,23 @@ UNIT_TEST(Booking_GetMinPrice)
}
}
-UNIT_TEST(GetHotelInfo)
+UNIT_CLASS_TEST(AsyncGuiThread, GetHotelInfo)
{
-// string const kHotelId = "0"; // Internal hotel id for testing.
-// booking::Api api;
-// booking::HotelInfo info;
-
-// api.GetHotelInfo(kHotelId, "en", [&info](booking::HotelInfo const & i)
-// {
-// info = i;
-// testing::StopEventLoop();
-// });
-// testing::RunEventLoop();
-
-// TEST_EQUAL(info.m_hotelId, kHotelId, ());
-// TEST(!info.m_description.empty(), ());
-// TEST_EQUAL(info.m_photos.size(), 2, ());
-// TEST_EQUAL(info.m_facilities.size(), 7, ());
-// TEST_EQUAL(info.m_reviews.size(), 4, ());
+ string const kHotelId = "0"; // Internal hotel id for testing.
+ booking::Api api;
+ booking::HotelInfo info;
+
+ api.GetHotelInfo(kHotelId, "en", [&info](booking::HotelInfo const & i)
+ {
+ info = i;
+ testing::Notify();
+ });
+ testing::Wait();
+
+ TEST_EQUAL(info.m_hotelId, kHotelId, ());
+ TEST(!info.m_description.empty(), ());
+ TEST_EQUAL(info.m_photos.size(), 2, ());
+ TEST_EQUAL(info.m_facilities.size(), 7, ());
+ TEST_EQUAL(info.m_reviews.size(), 4, ());
}
}
diff --git a/partners_api/partners_api_tests/cian_tests.cpp b/partners_api/partners_api_tests/cian_tests.cpp
index 51c6b37d0d..e4bd69b650 100644
--- a/partners_api/partners_api_tests/cian_tests.cpp
+++ b/partners_api/partners_api_tests/cian_tests.cpp
@@ -1,9 +1,13 @@
#include "testing/testing.hpp"
+#include "partners_api/partners_api_tests/async_gui_thread.hpp"
+
#include "partners_api/cian_api.hpp"
#include "3party/jansson/myjansson.hpp"
+using namespace partners_api;
+
namespace
{
UNIT_TEST(Cian_GetRentNearbyRaw)
@@ -16,7 +20,7 @@ UNIT_TEST(Cian_GetRentNearbyRaw)
TEST(json_is_object(root.get()), ());
}
-UNIT_TEST(Cian_GetRentNearby)
+UNIT_CLASS_TEST(AsyncGuiThread, Cian_GetRentNearby)
{
ms::LatLon latlon(55.807385, 37.505554);
uint64_t reqId = 0;
@@ -30,14 +34,14 @@ UNIT_TEST(Cian_GetRentNearby)
[&reqId, &result](std::vector<cian::RentPlace> const & places, uint64_t const requestId) {
TEST_EQUAL(reqId, requestId, ());
result = places;
- testing::StopEventLoop();
+ testing::Notify();
},
[&reqId](int httpCode, uint64_t const requestId) {
TEST_EQUAL(reqId, requestId, ());
TEST(false, (httpCode));
});
- testing::RunEventLoop();
+ testing::Wait();
TEST(!result.empty(), ());
for (auto const & r : result)
@@ -62,10 +66,10 @@ UNIT_TEST(Cian_GetRentNearby)
[&reqId, &httpCode](int code, uint64_t const requestId) {
TEST_EQUAL(reqId, requestId, ());
httpCode = code;
- testing::StopEventLoop();
+ testing::Notify();
});
- testing::RunEventLoop();
+ testing::Wait();
TEST_NOT_EQUAL(httpCode, -1, ());
}
diff --git a/partners_api/partners_api_tests/partners_api_tests.pro b/partners_api/partners_api_tests/partners_api_tests.pro
index 279bfc1bbd..399a9381d2 100644
--- a/partners_api/partners_api_tests/partners_api_tests.pro
+++ b/partners_api/partners_api_tests/partners_api_tests.pro
@@ -36,3 +36,6 @@ SOURCES += \
uber_tests.cpp \
viator_tests.cpp \
yandex_tests.cpp \
+
+HEADERS += \
+ async_gui_thread.hpp
diff --git a/partners_api/partners_api_tests/taxi_engine_tests.cpp b/partners_api/partners_api_tests/taxi_engine_tests.cpp
index 4011e2eb47..1a7489e973 100644
--- a/partners_api/partners_api_tests/taxi_engine_tests.cpp
+++ b/partners_api/partners_api_tests/taxi_engine_tests.cpp
@@ -1,12 +1,20 @@
#include "testing/testing.hpp"
+#include "partners_api/partners_api_tests/async_gui_thread.hpp"
+
#include "partners_api/taxi_engine.hpp"
#include "partners_api/uber_api.hpp"
#include "partners_api/yandex_api.hpp"
+#include "platform/gui_thread.hpp"
+
#include "geometry/latlon.hpp"
+#include "base/scope_guard.hpp"
#include "base/stl_add.hpp"
+#include "base/worker_thread.hpp"
+
+using namespace partners_api;
namespace
{
@@ -159,7 +167,7 @@ bool CompareProviders(taxi::ProvidersContainer const & lhs, taxi::ProvidersConta
return true;
}
-UNIT_TEST(TaxiEngine_ResultMaker)
+UNIT_CLASS_TEST(AsyncGuiThread, TaxiEngine_ResultMaker)
{
taxi::ResultMaker maker;
uint64_t reqId = 1;
@@ -170,6 +178,7 @@ UNIT_TEST(TaxiEngine_ResultMaker)
uint64_t const requestId) {
TEST_EQUAL(reqId, requestId, ());
providers = products;
+ testing::Notify();
};
auto const successNotPossibleCallback =
@@ -181,6 +190,7 @@ UNIT_TEST(TaxiEngine_ResultMaker)
uint64_t const requestId) {
TEST_EQUAL(reqId, requestId, ());
errors = e;
+ testing::Notify();
};
auto const errorNotPossibleCallback = [&reqId](taxi::ErrorsContainer const errors,
@@ -217,6 +227,8 @@ UNIT_TEST(TaxiEngine_ResultMaker)
maker.DecrementRequestCount(reqId);
maker.MakeResult(reqId);
+ testing::Wait();
+
TEST_EQUAL(providers.size(), 2, ());
TEST_EQUAL(providers[0].GetType(), taxi::Provider::Type::Uber, ());
TEST_EQUAL(providers[1].GetType(), taxi::Provider::Type::Yandex, ());
@@ -232,6 +244,8 @@ UNIT_TEST(TaxiEngine_ResultMaker)
maker.ProcessProducts(reqId, taxi::Provider::Type::Yandex, products2);
maker.MakeResult(reqId);
+ testing::Wait();
+
TEST_EQUAL(providers.size(), 1, ());
TEST_EQUAL(providers[0].GetType(), taxi::Provider::Type::Yandex, ());
TEST_EQUAL(providers[0][0].m_productId, "4", ());
@@ -243,6 +257,8 @@ UNIT_TEST(TaxiEngine_ResultMaker)
maker.ProcessError(reqId, taxi::Provider::Type::Yandex, taxi::ErrorCode::RemoteError);
maker.MakeResult(reqId);
+ testing::Wait();
+
TEST_EQUAL(errors.size(), 2, ());
TEST_EQUAL(errors[0].m_type, taxi::Provider::Type::Uber, ());
TEST_EQUAL(errors[0].m_code, taxi::ErrorCode::NoProducts, ());
@@ -253,9 +269,11 @@ UNIT_TEST(TaxiEngine_ResultMaker)
maker.DecrementRequestCount(reqId);
maker.DecrementRequestCount(reqId);
maker.MakeResult(reqId);
+
+ testing::Wait();
}
-UNIT_TEST(TaxiEngine_Smoke)
+UNIT_CLASS_TEST(AsyncGuiThread, TaxiEngine_Smoke)
{
// Used to synchronize access into GetAvailableProducts callback method.
std::mutex resultsMutex;
diff --git a/partners_api/partners_api_tests/uber_tests.cpp b/partners_api/partners_api_tests/uber_tests.cpp
index 642dd20e50..974222f628 100644
--- a/partners_api/partners_api_tests/uber_tests.cpp
+++ b/partners_api/partners_api_tests/uber_tests.cpp
@@ -178,14 +178,14 @@ UNIT_TEST(Uber_GetAvailableProducts)
[&resultProducts, &counter](std::vector<taxi::Product> const & products) {
resultProducts = products;
++counter;
- GetPlatform().RunOnGuiThread([] { testing::StopEventLoop(); });
+ testing::Notify();
},
[](taxi::ErrorCode const code) {
TEST(false, (code));
- GetPlatform().RunOnGuiThread([=] { testing::StopEventLoop(); });
+ testing::Notify();
});
- testing::RunEventLoop();
+ testing::Wait();
TEST(!resultProducts.empty(), ());
TEST_EQUAL(counter, 1, ());
@@ -196,15 +196,15 @@ UNIT_TEST(Uber_GetAvailableProducts)
api.GetAvailableProducts(from, farPos,
[](std::vector<taxi::Product> const & products) {
TEST(false, ());
- GetPlatform().RunOnGuiThread([] { testing::StopEventLoop(); });
+ testing::Notify();
},
[&errorCode, &counter](taxi::ErrorCode const code) {
errorCode = code;
++counter;
- GetPlatform().RunOnGuiThread([=] { testing::StopEventLoop(); });
+ testing::Notify();
});
- testing::RunEventLoop();
+ testing::Wait();
TEST_EQUAL(errorCode, taxi::ErrorCode::NoProducts, ());
TEST_EQUAL(counter, 1, ());
diff --git a/partners_api/partners_api_tests/viator_tests.cpp b/partners_api/partners_api_tests/viator_tests.cpp
index c3afa682b2..ccd726028f 100644
--- a/partners_api/partners_api_tests/viator_tests.cpp
+++ b/partners_api/partners_api_tests/viator_tests.cpp
@@ -1,5 +1,7 @@
#include "testing/testing.hpp"
+#include "partners_api/partners_api_tests/async_gui_thread.hpp"
+
#include "partners_api/viator_api.hpp"
#include <algorithm>
@@ -9,6 +11,8 @@
#include "3party/jansson/myjansson.hpp"
+using namespace partners_api;
+
namespace
{
UNIT_TEST(Viator_GetTopProducts)
@@ -24,7 +28,7 @@ UNIT_TEST(Viator_GetTopProducts)
TEST(success, ());
}
-UNIT_TEST(Viator_GetTop5Products)
+UNIT_CLASS_TEST(AsyncGuiThread, Viator_GetTop5Products)
{
viator::Api api;
std::string const kSofia = "5630";
@@ -37,10 +41,10 @@ UNIT_TEST(Viator_GetTop5Products)
resultId = destId;
resultProducts = products;
- testing::StopEventLoop();
+ testing::Notify();
});
- testing::RunEventLoop();
+ testing::Wait();
TEST_EQUAL(resultId, kSofia, ());
TEST(!resultProducts.empty(), ());
@@ -57,10 +61,10 @@ UNIT_TEST(Viator_GetTop5Products)
resultId = destId;
resultProducts = products;
- testing::StopEventLoop();
+ testing::Notify();
});
- testing::RunEventLoop();
+ testing::Wait();
TEST_EQUAL(resultId, kSofia, ());
TEST(!resultProducts.empty(), ());
@@ -77,10 +81,10 @@ UNIT_TEST(Viator_GetTop5Products)
resultId = destId;
resultProducts = products;
- testing::StopEventLoop();
+ testing::Notify();
});
- testing::RunEventLoop();
+ testing::Wait();
TEST_EQUAL(resultId, kSofia, ());
TEST(!resultProducts.empty(), ());
diff --git a/partners_api/partners_api_tests/yandex_tests.cpp b/partners_api/partners_api_tests/yandex_tests.cpp
index 1152fb9af2..622ca4444d 100644
--- a/partners_api/partners_api_tests/yandex_tests.cpp
+++ b/partners_api/partners_api_tests/yandex_tests.cpp
@@ -30,14 +30,13 @@ UNIT_TEST(Yandex_GetAvailableProducts)
api.GetAvailableProducts(from, to,
[&resultProducts](std::vector<taxi::Product> const & products) {
resultProducts = products;
- GetPlatform().RunOnGuiThread([] { testing::StopEventLoop(); });
+ testing::Notify();
},
[](taxi::ErrorCode const code) {
TEST(false, (code));
- GetPlatform().RunOnGuiThread([] { testing::StopEventLoop(); });
});
- testing::RunEventLoop();
+ testing::Wait();
TEST(!resultProducts.empty(), ());
@@ -46,15 +45,14 @@ UNIT_TEST(Yandex_GetAvailableProducts)
api.GetAvailableProducts(from, farPos,
[](std::vector<taxi::Product> const & products) {
TEST(false, ());
- GetPlatform().RunOnGuiThread([] { testing::StopEventLoop(); });
},
[&errorCode](taxi::ErrorCode const code) {
errorCode = code;
- GetPlatform().RunOnGuiThread([] { testing::StopEventLoop(); });
+ testing::Notify();
});
- TEST_EQUAL(errorCode, taxi::ErrorCode::NoProducts, ());
+ testing::Wait();
- testing::RunEventLoop();
+ TEST_EQUAL(errorCode, taxi::ErrorCode::NoProducts, ());
}
} // namespace
diff --git a/partners_api/taxi_engine.hpp b/partners_api/taxi_engine.hpp
index 85d8a4d453..24a69d7bb4 100644
--- a/partners_api/taxi_engine.hpp
+++ b/partners_api/taxi_engine.hpp
@@ -2,6 +2,8 @@
#include "partners_api/taxi_base.hpp"
+#include "platform/safe_callback.hpp"
+
#include <cstdint>
#include <memory>
#include <mutex>
@@ -10,9 +12,10 @@
namespace taxi
{
using SuccessCallback =
- std::function<void(ProvidersContainer const & products, uint64_t const requestId)>;
+ platform::SafeCallback<void(ProvidersContainer const & products, uint64_t const requestId)>;
-using ErrorCallback = std::function<void(ErrorsContainer const & errors, uint64_t const requestId)>;
+using ErrorCallback =
+ platform::SafeCallback<void(ErrorsContainer const & errors, uint64_t const requestId)>;
class Delegate
{
diff --git a/partners_api/viator_api.hpp b/partners_api/viator_api.hpp
index 363ed06132..437234f56f 100644
--- a/partners_api/viator_api.hpp
+++ b/partners_api/viator_api.hpp
@@ -1,5 +1,7 @@
#pragma once
+#include "platform/safe_callback.hpp"
+
#include <functional>
#include <string>
#include <vector>
@@ -28,7 +30,7 @@ struct Product
};
using GetTop5ProductsCallback =
- std::function<void(std::string const & destId, std::vector<Product> const & products)>;
+ platform::SafeCallback<void(std::string const & destId, std::vector<Product> const & products)>;
class Api
{
diff --git a/platform/platform.pro b/platform/platform.pro
index d0f06499a8..e5781f82b3 100644
--- a/platform/platform.pro
+++ b/platform/platform.pro
@@ -93,6 +93,7 @@ HEADERS += \
network_policy.hpp \
platform.hpp \
preferred_languages.hpp \
+ safe_callback.hpp \
servers_list.hpp \
settings.hpp \
socket.hpp \
diff --git a/platform/safe_callback.hpp b/platform/safe_callback.hpp
new file mode 100644
index 0000000000..313e095fc5
--- /dev/null
+++ b/platform/safe_callback.hpp
@@ -0,0 +1,41 @@
+#pragma once
+
+#include "platform/platform.hpp"
+
+#include <future>
+#include <functional>
+#include <utility>
+
+namespace platform
+{
+template <typename T>
+class SafeCallback;
+
+// Calls callback on main thread, all params are copied.
+// *NOTE* The class is not thread-safe.
+template <typename R, typename ...Args>
+class SafeCallback<R(Args...)>
+{
+public:
+ SafeCallback() = default;
+
+ template <typename Fn>
+ SafeCallback(Fn const & fn)
+ : m_fn(fn)
+ {
+ }
+
+ operator bool() const noexcept
+ {
+ return static_cast<bool>(m_fn);
+ }
+
+ void operator()(Args... args) const
+ {
+ GetPlatform().RunOnGuiThread(std::bind(m_fn, std::move(args)...));
+ }
+
+private:
+ std::function<R(Args...)> m_fn;
+};
+} // namespace platform
diff --git a/testing/testing.hpp b/testing/testing.hpp
index 4b0c872752..8d9d404c00 100644
--- a/testing/testing.hpp
+++ b/testing/testing.hpp
@@ -44,6 +44,9 @@ namespace testing
{
void RunEventLoop();
void StopEventLoop();
+
+void Wait();
+void Notify();
} // namespace testing
// This struct contains parsed command line options. It may contain pointers to argc contents.
diff --git a/testing/testingmain.cpp b/testing/testingmain.cpp
index 60af721c4e..35d1a24348 100644
--- a/testing/testingmain.cpp
+++ b/testing/testingmain.cpp
@@ -4,7 +4,9 @@
#include "base/logging.hpp"
#include "base/string_utils.hpp"
#include "base/timer.hpp"
+#include "base/waiter.hpp"
+#include "std/chrono.hpp"
#include "std/cstring.hpp"
#include "std/iomanip.hpp"
#include "std/iostream.hpp"
@@ -32,6 +34,10 @@
#endif
#endif
+namespace
+{
+base::Waiter g_waiter;
+} // namespace
namespace testing
{
@@ -53,6 +59,16 @@ void StopEventLoop()
#endif
}
+void Wait()
+{
+ g_waiter.Wait();
+ g_waiter.Reset();
+}
+
+void Notify()
+{
+ g_waiter.Notify();
+}
} // namespace testing
namespace
diff --git a/xcode/base/base.xcodeproj/project.pbxproj b/xcode/base/base.xcodeproj/project.pbxproj
index d874e62418..ef9c0a7bcc 100644
--- a/xcode/base/base.xcodeproj/project.pbxproj
+++ b/xcode/base/base.xcodeproj/project.pbxproj
@@ -45,6 +45,7 @@
39FD27391CC65AD000AFF551 /* timer_test.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 39FD26E31CC65A0E00AFF551 /* timer_test.cpp */; };
39FD273B1CC65B1000AFF551 /* libbase.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 675341771A3F57BF00A0A8C3 /* libbase.a */; };
3D7815731F3A145F0068B6AC /* task_loop.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 3D7815711F3A145F0068B6AC /* task_loop.hpp */; };
+ 3D78157B1F3D89EC0068B6AC /* waiter.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 3D78157A1F3D89EC0068B6AC /* waiter.hpp */; };
56B1A0741E69DE4D00395022 /* random.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 56B1A0711E69DE4D00395022 /* random.cpp */; };
56B1A0751E69DE4D00395022 /* random.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 56B1A0721E69DE4D00395022 /* random.hpp */; };
56B1A0761E69DE4D00395022 /* small_set.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 56B1A0731E69DE4D00395022 /* small_set.hpp */; };
@@ -164,6 +165,7 @@
39FD27401CC65B2800AFF551 /* libindexer.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libindexer.a; path = "../../../omim-xcode-build/Debug/libindexer.a"; sourceTree = "<group>"; };
39FD27421CC65B4800AFF551 /* libcoding.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libcoding.a; path = "../../../omim-xcode-build/Debug/libcoding.a"; sourceTree = "<group>"; };
3D7815711F3A145F0068B6AC /* task_loop.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = task_loop.hpp; sourceTree = "<group>"; };
+ 3D78157A1F3D89EC0068B6AC /* waiter.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = waiter.hpp; sourceTree = "<group>"; };
56B1A0711E69DE4D00395022 /* random.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = random.cpp; sourceTree = "<group>"; };
56B1A0721E69DE4D00395022 /* random.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = random.hpp; sourceTree = "<group>"; };
56B1A0731E69DE4D00395022 /* small_set.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = small_set.hpp; sourceTree = "<group>"; };
@@ -323,6 +325,7 @@
675341791A3F57BF00A0A8C3 /* base */ = {
isa = PBXGroup;
children = (
+ 3D78157A1F3D89EC0068B6AC /* waiter.hpp */,
3D7815711F3A145F0068B6AC /* task_loop.hpp */,
F6F8E3C61EF846CE00F2DE8F /* worker_thread.cpp */,
F6F8E3C71EF846CE00F2DE8F /* worker_thread.hpp */,
@@ -464,6 +467,7 @@
675341D01A3F57E400A0A8C3 /* buffer_vector.hpp in Headers */,
675341FC1A3F57E400A0A8C3 /* std_serialization.hpp in Headers */,
675342091A3F57E400A0A8C3 /* thread.hpp in Headers */,
+ 3D78157B1F3D89EC0068B6AC /* waiter.hpp in Headers */,
675341CC1A3F57E400A0A8C3 /* assert.hpp in Headers */,
675341E01A3F57E400A0A8C3 /* logging.hpp in Headers */,
675341FB1A3F57E400A0A8C3 /* stats.hpp in Headers */,
diff --git a/xcode/partners_api/partners_api.xcodeproj/project.pbxproj b/xcode/partners_api/partners_api.xcodeproj/project.pbxproj
index 553e9f9b91..9a8d54605a 100644
--- a/xcode/partners_api/partners_api.xcodeproj/project.pbxproj
+++ b/xcode/partners_api/partners_api.xcodeproj/project.pbxproj
@@ -28,6 +28,7 @@
3D47B2AD1F14BE89000828D2 /* cian_api.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 3D47B2AB1F14BE89000828D2 /* cian_api.hpp */; };
3D47B2AF1F14BE94000828D2 /* cian_tests.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3D47B2AE1F14BE94000828D2 /* cian_tests.cpp */; };
3D47B2B11F14FA14000828D2 /* utils.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 3D47B2B01F14FA14000828D2 /* utils.hpp */; };
+ 3D7815761F3A14910068B6AC /* async_gui_thread.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 3D7815751F3A14910068B6AC /* async_gui_thread.hpp */; };
3DBC1C541E4B14920016897F /* facebook_ads.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3DBC1C521E4B14920016897F /* facebook_ads.cpp */; };
3DBC1C551E4B14920016897F /* facebook_ads.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 3DBC1C531E4B14920016897F /* facebook_ads.hpp */; };
3DFEBF851EF82BEA00317D5C /* viator_api.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3DFEBF831EF82BEA00317D5C /* viator_api.cpp */; };
@@ -83,6 +84,7 @@
3D47B2AB1F14BE89000828D2 /* cian_api.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = cian_api.hpp; sourceTree = "<group>"; };
3D47B2AE1F14BE94000828D2 /* cian_tests.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = cian_tests.cpp; sourceTree = "<group>"; };
3D47B2B01F14FA14000828D2 /* utils.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = utils.hpp; sourceTree = "<group>"; };
+ 3D7815751F3A14910068B6AC /* async_gui_thread.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = async_gui_thread.hpp; sourceTree = "<group>"; };
3DBC1C501E4B14810016897F /* facebook_tests.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = facebook_tests.cpp; sourceTree = "<group>"; };
3DBC1C521E4B14920016897F /* facebook_ads.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = facebook_ads.cpp; sourceTree = "<group>"; };
3DBC1C531E4B14920016897F /* facebook_ads.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = facebook_ads.hpp; sourceTree = "<group>"; };
@@ -208,6 +210,7 @@
F6B536441DA521060067EEA5 /* partners_api_tests */ = {
isa = PBXGroup;
children = (
+ 3D7815751F3A14910068B6AC /* async_gui_thread.hpp */,
3D47B2AE1F14BE94000828D2 /* cian_tests.cpp */,
3D47B2801F00F94D000828D2 /* mopub_tests.cpp */,
3DFEBF871EF82C1300317D5C /* viator_tests.cpp */,
@@ -256,6 +259,7 @@
3D47B29C1F054C89000828D2 /* taxi_countries.hpp in Headers */,
346E88971E9D087400D4CE9B /* ads_base.hpp in Headers */,
3D47B29D1F054C89000828D2 /* taxi_places.hpp in Headers */,
+ 3D7815761F3A14910068B6AC /* async_gui_thread.hpp in Headers */,
F67E75261DB8F06F00D6741F /* opentable_api.hpp in Headers */,
F6B536411DA520E40067EEA5 /* booking_api.hpp in Headers */,
3430643D1E9FBCF500DC7665 /* mopub_ads.hpp in Headers */,
diff --git a/xcode/platform/platform.xcodeproj/project.pbxproj b/xcode/platform/platform.xcodeproj/project.pbxproj
index 55be126a76..54b6f63a87 100644
--- a/xcode/platform/platform.xcodeproj/project.pbxproj
+++ b/xcode/platform/platform.xcodeproj/project.pbxproj
@@ -17,6 +17,7 @@
3D30587F1D880910004AC712 /* http_client_apple.mm in Sources */ = {isa = PBXBuildFile; fileRef = 3D30587E1D880910004AC712 /* http_client_apple.mm */; };
3D78156E1F3A14090068B6AC /* gui_thread_apple.mm in Sources */ = {isa = PBXBuildFile; fileRef = 3D78156B1F3A14090068B6AC /* gui_thread_apple.mm */; };
3D78156F1F3A14090068B6AC /* gui_thread.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 3D78156C1F3A14090068B6AC /* gui_thread.hpp */; };
+ 3D78157D1F3D8A0A0068B6AC /* safe_callback.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 3D78157C1F3D8A0A0068B6AC /* safe_callback.hpp */; };
3D97F64B1D9C05E800380945 /* http_client.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3D97F64A1D9C05E800380945 /* http_client.cpp */; };
3DE8B98F1DEC3115000E6083 /* network_policy.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 3DE8B98E1DEC3115000E6083 /* network_policy.hpp */; };
56EB1EDC1C6B6E6C0022D831 /* file_logging.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 56EB1ED81C6B6E6C0022D831 /* file_logging.cpp */; };
@@ -119,6 +120,7 @@
3D30587E1D880910004AC712 /* http_client_apple.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = http_client_apple.mm; sourceTree = "<group>"; };
3D78156B1F3A14090068B6AC /* gui_thread_apple.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = gui_thread_apple.mm; sourceTree = "<group>"; };
3D78156C1F3A14090068B6AC /* gui_thread.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = gui_thread.hpp; sourceTree = "<group>"; };
+ 3D78157C1F3D8A0A0068B6AC /* safe_callback.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = safe_callback.hpp; sourceTree = "<group>"; };
3D97F64A1D9C05E800380945 /* http_client.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = http_client.cpp; sourceTree = "<group>"; };
3DE8B98E1DEC3115000E6083 /* network_policy.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = network_policy.hpp; sourceTree = "<group>"; };
56EB1ED81C6B6E6C0022D831 /* file_logging.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = file_logging.cpp; sourceTree = "<group>"; };
@@ -328,6 +330,7 @@
6753437A1A3F5CF500A0A8C3 /* platform */ = {
isa = PBXGroup;
children = (
+ 3D78157C1F3D8A0A0068B6AC /* safe_callback.hpp */,
3D78156B1F3A14090068B6AC /* gui_thread_apple.mm */,
3D78156C1F3A14090068B6AC /* gui_thread.hpp */,
675343861A3F5D5900A0A8C3 /* apple_location_service.mm */,
@@ -444,6 +447,7 @@
676C84211C64CD3300DC9603 /* mwm_traits.hpp in Headers */,
675343B41A3F5D5A00A0A8C3 /* chunks_download_strategy.hpp in Headers */,
67247FFE1C60BD6500EDE56A /* writable_dir_changer.hpp in Headers */,
+ 3D78157D1F3D8A0A0068B6AC /* safe_callback.hpp in Headers */,
3D78156F1F3A14090068B6AC /* gui_thread.hpp in Headers */,
674125091B4C00CC00A3E828 /* country_defines.hpp in Headers */,
675343CD1A3F5D5A00A0A8C3 /* platform.hpp in Headers */,