diff --git a/change/react-native-windows-dce01c53-5395-463d-bbfd-9162cd9f309d.json b/change/react-native-windows-dce01c53-5395-463d-bbfd-9162cd9f309d.json new file mode 100644 index 00000000000..6f9c48cce80 --- /dev/null +++ b/change/react-native-windows-dce01c53-5395-463d-bbfd-9162cd9f309d.json @@ -0,0 +1,7 @@ +{ + "type": "prerelease", + "comment": "C++ 20: Move vnext to C++ 20 and C++ 20 coroutines", + "packageName": "react-native-windows", + "email": "ngerlem@fb.com", + "dependentChangeType": "patch" +} diff --git a/vnext/Desktop.UnitTests/React.Windows.Desktop.UnitTests.vcxproj b/vnext/Desktop.UnitTests/React.Windows.Desktop.UnitTests.vcxproj index c117e37a61e..6cfa6a9194a 100644 --- a/vnext/Desktop.UnitTests/React.Windows.Desktop.UnitTests.vcxproj +++ b/vnext/Desktop.UnitTests/React.Windows.Desktop.UnitTests.vcxproj @@ -69,7 +69,6 @@ $(VCInstallDir)UnitTest\include; %(AdditionalIncludeDirectories) - %(AdditionalOptions) /await diff --git a/vnext/Microsoft.ReactNative/Microsoft.ReactNative.vcxproj b/vnext/Microsoft.ReactNative/Microsoft.ReactNative.vcxproj index d14e1c1910a..10617b136f4 100644 --- a/vnext/Microsoft.ReactNative/Microsoft.ReactNative.vcxproj +++ b/vnext/Microsoft.ReactNative/Microsoft.ReactNative.vcxproj @@ -95,7 +95,7 @@ $(IntDir)pch.pch pch.h Level4 - /await %(AdditionalOptions) /bigobj /ZH:SHA_256 + %(AdditionalOptions) /bigobj /ZH:SHA_256 $(FmtDir)\include; $(ReactNativeWindowsDir)Microsoft.ReactNative; diff --git a/vnext/Microsoft.ReactNative/Utils/LocalBundleReader.cpp b/vnext/Microsoft.ReactNative/Utils/LocalBundleReader.cpp index 08e5fe4d20b..9f8d8fdcf1f 100644 --- a/vnext/Microsoft.ReactNative/Utils/LocalBundleReader.cpp +++ b/vnext/Microsoft.ReactNative/Utils/LocalBundleReader.cpp @@ -53,7 +53,8 @@ std::string GetBundleFromEmbeddedResource(const winrt::Windows::Foundation::Uri return std::string(start, start + size); } -std::future LocalBundleReader::LoadBundleAsync(const std::wstring bundleUri) { +winrt::Windows::Foundation::IAsyncOperation LocalBundleReader::LoadBundleAsync( + const std::wstring bundleUri) { co_await winrt::resume_background(); winrt::Windows::Storage::StorageFile file{nullptr}; @@ -65,7 +66,7 @@ std::future LocalBundleReader::LoadBundleAsync(const std::wstring b file = co_await winrt::Windows::Storage::StorageFile::GetFileFromApplicationUriAsync(uri); } else if (bundleUri._Starts_with(L"resource://")) { winrt::Windows::Foundation::Uri uri(bundleUri); - co_return GetBundleFromEmbeddedResource(uri); + co_return winrt::to_hstring(GetBundleFromEmbeddedResource(uri)); } else { file = co_await winrt::Windows::Storage::StorageFile::GetFileFromPathAsync(bundleUri); } @@ -86,10 +87,10 @@ std::future LocalBundleReader::LoadBundleAsync(const std::wstring b reinterpret_cast(&script[0]), reinterpret_cast(&script[script.length()])}); dataReader.Close(); - co_return script; + co_return winrt::to_hstring(script); } -std::string LocalBundleReader::LoadBundle(const std::wstring &bundlePath) { +winrt::hstring LocalBundleReader::LoadBundle(const std::wstring &bundlePath) { return LoadBundleAsync(bundlePath).get(); } @@ -113,7 +114,7 @@ size_t StorageFileBigString::size() const { void StorageFileBigString::ensure() const { if (m_string.empty()) { - m_string = m_futureBuffer.get(); + m_string = winrt::to_string(m_futureBuffer.get()); } } diff --git a/vnext/Microsoft.ReactNative/Utils/LocalBundleReader.h b/vnext/Microsoft.ReactNative/Utils/LocalBundleReader.h index 8671ebf59ee..12c8bda970a 100644 --- a/vnext/Microsoft.ReactNative/Utils/LocalBundleReader.h +++ b/vnext/Microsoft.ReactNative/Utils/LocalBundleReader.h @@ -3,15 +3,15 @@ #pragma once #include -#include +#include #include namespace Microsoft::ReactNative { class LocalBundleReader { public: - static std::future LoadBundleAsync(const std::wstring bundlePath); - static std::string LoadBundle(const std::wstring &bundlePath); + static winrt::Windows::Foundation::IAsyncOperation LoadBundleAsync(const std::wstring bundleUri); + static winrt::hstring LoadBundle(const std::wstring &bundlePath); }; class StorageFileBigString : public facebook::react::JSBigString { @@ -24,7 +24,7 @@ class StorageFileBigString : public facebook::react::JSBigString { void ensure() const; private: - mutable std::future m_futureBuffer; + mutable winrt::Windows::Foundation::IAsyncOperation m_futureBuffer; mutable std::string m_string; }; diff --git a/vnext/Microsoft.ReactNative/Utils/UwpScriptStore.cpp b/vnext/Microsoft.ReactNative/Utils/UwpScriptStore.cpp index 59bb0c805db..0130afcdfda 100644 --- a/vnext/Microsoft.ReactNative/Utils/UwpScriptStore.cpp +++ b/vnext/Microsoft.ReactNative/Utils/UwpScriptStore.cpp @@ -43,7 +43,8 @@ facebook::jsi::ScriptVersion_t UwpScriptStore::getScriptVersion(const std::strin return version; } -std::future UwpScriptStore::getScriptVersionAsync(const std::string &bundleUri) { +winrt::Windows::Foundation::IAsyncOperation UwpScriptStore::getScriptVersionAsync( + const std::string &bundleUri) { co_await winrt::resume_background(); const winrt::hstring fileUrl(Microsoft::Common::Unicode::Utf8ToUtf16("ms-appx:///Bundle/" + bundleUri + ".bundle")); diff --git a/vnext/Microsoft.ReactNative/Utils/UwpScriptStore.h b/vnext/Microsoft.ReactNative/Utils/UwpScriptStore.h index 6b77db3f9e7..78b1ff112ae 100644 --- a/vnext/Microsoft.ReactNative/Utils/UwpScriptStore.h +++ b/vnext/Microsoft.ReactNative/Utils/UwpScriptStore.h @@ -1,6 +1,6 @@ #pragma once #include -#include +#include namespace Microsoft::ReactNative { @@ -16,7 +16,8 @@ class UwpScriptStore : public facebook::jsi::ScriptStore { static facebook::jsi::ScriptVersion_t GetFileVersion(const std::wstring &filePath); private: - std::future getScriptVersionAsync(const std::string &bundleUri); + winrt::Windows::Foundation::IAsyncOperation getScriptVersionAsync( + const std::string &bundleUri); }; } // namespace Microsoft::ReactNative diff --git a/vnext/Mso.UnitTests/Mso.UnitTests.vcxproj b/vnext/Mso.UnitTests/Mso.UnitTests.vcxproj index 65e4c389605..bfda7bc3af2 100644 --- a/vnext/Mso.UnitTests/Mso.UnitTests.vcxproj +++ b/vnext/Mso.UnitTests/Mso.UnitTests.vcxproj @@ -62,7 +62,7 @@ $(IntDir)pch.pch _CONSOLE;MS_TARGET_WINDOWS;MSO_MOTIFCPP;%(PreprocessorDefinitions) Level4 - /await %(AdditionalOptions) /bigobj + %(AdditionalOptions) /bigobj true Cdecl @@ -148,4 +148,4 @@ - \ No newline at end of file + diff --git a/vnext/PropertySheets/React.Cpp.props b/vnext/PropertySheets/React.Cpp.props index bc7739fe4f2..bf946633f95 100644 --- a/vnext/PropertySheets/React.Cpp.props +++ b/vnext/PropertySheets/React.Cpp.props @@ -152,4 +152,4 @@ - \ No newline at end of file + diff --git a/vnext/Shared/DevSupportManager.cpp b/vnext/Shared/DevSupportManager.cpp index a6935bb8aa9..53e54ed07d8 100644 --- a/vnext/Shared/DevSupportManager.cpp +++ b/vnext/Shared/DevSupportManager.cpp @@ -15,6 +15,7 @@ #include "Utilities.h" #include +#include #include #include #include @@ -30,7 +31,6 @@ #include #pragma warning(pop) -#include #include #include @@ -44,7 +44,9 @@ using namespace facebook::react; namespace Microsoft::ReactNative { -std::future> GetJavaScriptFromServerAsync(const std::string &url) { +winrt::Windows::Foundation::IAsyncOperation< + winrt::Windows::Foundation::Collections::IKeyValuePair> +GetJavaScriptFromServerAsync(const std::string &url) { winrt::Windows::Web::Http::Filters::HttpBaseProtocolFilter filter; filter.CacheControl().ReadBehavior(winrt::Windows::Web::Http::Filters::HttpCacheReadBehavior::NoCache); winrt::Windows::Web::Http::HttpClient httpClient(filter); @@ -58,8 +60,9 @@ std::future> GetJavaScriptFromServerAsync(const std try { winrt::Windows::Web::Http::HttpResponseMessage response = co_await asyncRequest; } catch (winrt::hresult_error const &e) { - co_return std::make_pair( - Microsoft::Common::Unicode::Utf16ToUtf8(e.message().c_str(), e.message().size()).c_str(), false); + co_return winrt::pair( + winrt::to_hstring(Microsoft::Common::Unicode::Utf16ToUtf8(e.message().c_str(), e.message().size()).c_str()), + false); } #else co_await lessthrow_await_adapter> GetJavaScriptFromServerAsync(const std } else { error = fmt::format("Error 0x{:x} downloading {}.", static_cast(asyncRequest.ErrorCode()), url); } - co_return std::make_pair(error, false); + co_return winrt::pair(winrt::to_hstring(error), false); } winrt::Windows::Web::Http::HttpResponseMessage response = asyncRequest.GetResults(); @@ -98,7 +101,7 @@ std::future> GetJavaScriptFromServerAsync(const std result = fmt::format("HTTP Error {} downloading {}.", static_cast(response.StatusCode()), url); } - co_return std::make_pair(std::move(result), response.IsSuccessStatusCode()); + co_return winrt::pair(winrt::to_hstring(std::move(result)), response.IsSuccessStatusCode()); } void LaunchDevTools(const facebook::react::DevSettings &settings) { @@ -171,7 +174,8 @@ bool IsIgnorablePollHResult(HRESULT hr) { return hr == WININET_E_INVALID_SERVER_RESPONSE; } -std::future PollForLiveReload(const std::string &url) { +winrt::Windows::Foundation::IAsyncOperation PollForLiveReload( + const std::string url) { winrt::Windows::Web::Http::HttpClient httpClient; winrt::Windows::Foundation::Uri uri(Microsoft::Common::Unicode::Utf8ToUtf16(url)); httpClient.DefaultRequestHeaders().Connection().TryParseAdd(L"keep-alive"); @@ -290,7 +294,8 @@ std::pair GetJavaScriptFromServer( inlineSourceMap, hermesBytecodeVersion); try { - return GetJavaScriptFromServerAsync(bundleUrl).get(); + auto result = GetJavaScriptFromServerAsync(bundleUrl).get(); + return std::make_pair(winrt::to_string(result.Key()), result.Value()); } catch (winrt::hresult_error const &e) { return std::make_pair( "Error: " + Microsoft::Common::Unicode::Utf16ToUtf8(e.message().c_str(), e.message().size()), false); diff --git a/vnext/Shared/DevSupportManager.h b/vnext/Shared/DevSupportManager.h index 5c33ed1de02..ad95a39d9f3 100644 --- a/vnext/Shared/DevSupportManager.h +++ b/vnext/Shared/DevSupportManager.h @@ -7,6 +7,7 @@ #include +#include #include #include #include @@ -22,6 +23,29 @@ struct DevSettings; } } // namespace facebook +namespace winrt { + +template +struct pair_impl : implements, Windows::Foundation::Collections::IKeyValuePair> { + pair_impl(K k, V v) : m_k(k), m_v(v) {} + K Key() { + return m_k; + } + V Value() { + return m_v; + } + + private: + K m_k; + V m_v; +}; + +template +Windows::Foundation::Collections::IKeyValuePair pair(K key, V value) { + return make>(key, value); +} +} // namespace winrt + namespace Microsoft::ReactNative { std::pair GetJavaScriptFromServer( diff --git a/vnext/Shared/HermesSamplingProfiler.cpp b/vnext/Shared/HermesSamplingProfiler.cpp index 442dba36887..2c25e568ee2 100644 --- a/vnext/Shared/HermesSamplingProfiler.cpp +++ b/vnext/Shared/HermesSamplingProfiler.cpp @@ -5,7 +5,7 @@ #include #include -#include +#include #include "HermesRuntimeHolder.h" #include "HermesSamplingProfiler.h" @@ -32,10 +32,8 @@ auto resume_in_dispatcher(const IReactDispatcher &dispatcher) noexcept { void await_resume() const noexcept {} - void await_suspend(std::experimental::coroutine_handle<> resume) noexcept { - callback_ = [context = resume.address()]() noexcept { - std::experimental::coroutine_handle<>::from_address(context)(); - }; + void await_suspend(std::coroutine_handle<> resume) noexcept { + callback_ = [context = resume.address()]() noexcept { std::coroutine_handle<>::from_address(context)(); }; dispatcher_.Post(std::move(callback_)); } @@ -54,8 +52,7 @@ IAsyncOperation getTraceFilePath() noexcept { .count(); os << hermesDataPath.c_str() << L"\\cpu_" << now << L".cpuprofile"; - // TODO: Use C++ 20 `os.view()` to avoid a copy - co_return winrt::hstring(os.str()); + co_return winrt::hstring(os.view()); } } // namespace diff --git a/vnext/Shared/Networking/WinRTWebSocketResource.cpp b/vnext/Shared/Networking/WinRTWebSocketResource.cpp index aa227c00632..4b06f27b8f0 100644 --- a/vnext/Shared/Networking/WinRTWebSocketResource.cpp +++ b/vnext/Shared/Networking/WinRTWebSocketResource.cpp @@ -20,6 +20,7 @@ #include // Standard Library +#include #include using Microsoft::Common::Utilities::CheckedReinterpretCast; @@ -67,10 +68,8 @@ auto resume_in_queue(const Mso::DispatchQueue &queue) noexcept { void await_resume() const noexcept {} - void await_suspend(std::experimental::coroutine_handle<> resume) noexcept { - m_callback = [context = resume.address()]() noexcept { - std::experimental::coroutine_handle<>::from_address(context)(); - }; + void await_suspend(std::coroutine_handle<> resume) noexcept { + m_callback = [context = resume.address()]() noexcept { std::coroutine_handle<>::from_address(context)(); }; m_queue.Post(std::move(m_callback)); } diff --git a/vnext/Shared/Utils/CppWinrtLessExceptions.h b/vnext/Shared/Utils/CppWinrtLessExceptions.h index 9bd4b4fc323..83eddc1bc13 100644 --- a/vnext/Shared/Utils/CppWinrtLessExceptions.h +++ b/vnext/Shared/Utils/CppWinrtLessExceptions.h @@ -22,6 +22,7 @@ #define SHARED_UTILS_CPPWINRTLESSEXCEPTIONS_H_ #include +#include // #define DEFAULT_CPPWINRT_EXCEPTIONS #ifndef DEFAULT_CPPWINRT_EXCEPTIONS @@ -35,7 +36,7 @@ struct lessthrow_await_adapter { return async.Status() == winrt::Windows::Foundation::AsyncStatus::Completed; } - void await_suspend(std::experimental::coroutine_handle<> handle) const { + void await_suspend(std::coroutine_handle<> handle) const { auto context = winrt::capture(WINRT_IMPL_CoGetObjectContext); async.Completed([handle, context = std::move(context)](auto const &, winrt::Windows::Foundation::AsyncStatus) { @@ -43,7 +44,7 @@ struct lessthrow_await_adapter { args.data = handle.address(); auto callback = [](winrt::impl::com_callback_args *args) noexcept -> int32_t { - std::experimental::coroutine_handle<>::from_address(args->data)(); + std::coroutine_handle<>::from_address(args->data)(); return S_OK; };