Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"type": "prerelease",
"comment": "Implemented support for native module std::weak_ptr",
"packageName": "react-native-windows",
"email": "[email protected]",
"dependentChangeType": "patch",
"date": "2020-05-21T20:01:24.822Z"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"type": "prerelease",
"comment": "Fix ReactInstance error state to avoid crashes",
"packageName": "react-native-windows",
"email": "[email protected]",
"dependentChangeType": "patch",
"date": "2020-05-22T05:04:55.630Z"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"type": "prerelease",
"comment": "Add UIDispatcher property to ReactInstanceSettings and IReactContext",
"packageName": "react-native-windows",
"email": "[email protected]",
"dependentChangeType": "patch",
"date": "2020-05-25T22:56:21.049Z"
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
#include "DebugHelpers.h"
#include "NativeModules.h"

#define DEBUG_OUTPUT(...) DebugWriteLine("SampleModuleCppImpl", ##__VA_ARGS__);
#define DEBUG_OUTPUT(...) DebugWriteLine("SampleLibraryCpp", ##__VA_ARGS__);

namespace SampleLibraryCpp {

Expand Down Expand Up @@ -39,6 +39,7 @@ struct SampleModuleCppImpl {
DEBUG_OUTPUT("C++ Properties.Prop1:", *reactContext.Properties().Get(myProp1));
DEBUG_OUTPUT("C++ Properties.Prop2:", winrt::to_string(*reactContext.Properties().Get(myProp2)));

// Note that all notification subscriptions are removed automatically when React instance is unloaded.
m_timer = winrt::Windows::System::Threading::ThreadPoolTimer::CreatePeriodicTimer(
[this](const winrt::Windows::System::Threading::ThreadPoolTimer) noexcept {
TimedEvent(++m_timerCount);
Expand Down Expand Up @@ -246,4 +247,22 @@ struct SampleModuleCppImpl {
static constexpr std::chrono::milliseconds TimedEventInterval{5000};
};

// SampleSharedCppModule shows how to inherited native modules from std::enable_shared_from_this
// to use weak_from_this() in event handlers. In this example we use notifications instead
// of events just to show case the std::weak_ptr use.
REACT_MODULE(SampleSharedCppModule);
struct SampleSharedCppModule : std::enable_shared_from_this<SampleSharedCppModule> {
using IInspectable = winrt::Windows::Foundation::IInspectable;

// The Initialize method is called when React instance loaded JavaScript and the module is ready to use.
REACT_INIT(Initialize)
void Initialize(React::ReactContext const & /*reactContext*/) noexcept {}

REACT_METHOD(SayHello)
std::string SayHello() noexcept {
// This method is currently unused
return "Hello";
}
};

} // namespace SampleLibraryCpp
Original file line number Diff line number Diff line change
Expand Up @@ -141,12 +141,13 @@
<Midl Include="$(ReactNativeWindowsDir)Microsoft.ReactNative\IJSValueReader.idl" />
<Midl Include="$(ReactNativeWindowsDir)Microsoft.ReactNative\IJSValueWriter.idl" />
<Midl Include="$(ReactNativeWindowsDir)Microsoft.ReactNative\IReactContext.idl" />
<Midl Include="$(ReactNativeWindowsDir)Microsoft.ReactNative\IReactDispatcher.idl" />
<Midl Include="$(ReactNativeWindowsDir)Microsoft.ReactNative\IReactModuleBuilder.idl" />
<Midl Include="$(ReactNativeWindowsDir)Microsoft.ReactNative\IReactNonAbiValue.idl" />
<Midl Include="$(ReactNativeWindowsDir)Microsoft.ReactNative\IReactPackageBuilder.idl" />
<Midl Include="$(ReactNativeWindowsDir)Microsoft.ReactNative\IReactPropertyBag.idl" />
<Midl Include="$(ReactNativeWindowsDir)Microsoft.ReactNative\IViewManager.idl" />
<Midl Include="..\Microsoft.ReactNative\IReactNonAbiValue.idl" />
<Midl Include="..\Microsoft.ReactNative\IReactPropertyBag.idl" />
<Midl Include="..\Microsoft.ReactNative\NoExceptionAttribute.idl" />
<Midl Include="$(ReactNativeWindowsDir)Microsoft.ReactNative\NoExceptionAttribute.idl" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ struct ReactContextStub : implements<ReactContextStub, IReactContext> {
VerifyElseCrashSz(false, "Not implemented");
}

IReactDispatcher UIDispatcher() noexcept {
VerifyElseCrashSz(false, "Not implemented");
}

void DispatchEvent(
Windows::UI::Xaml::FrameworkElement const & /*view*/,
hstring const & /*eventName*/,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,10 @@ struct ReactContextMock : implements<ReactContextMock, IReactContext> {
VerifyElseCrashSz(false, "Not implemented");
}

IReactDispatcher UIDispatcher() noexcept {
VerifyElseCrashSz(false, "Not implemented");
}

void DispatchEvent(
FrameworkElement const & /*view*/,
hstring const & /*eventName*/,
Expand Down
2 changes: 1 addition & 1 deletion vnext/Microsoft.ReactNative.Cxx.UnitTests/pch.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@

#undef GetCurrentTime

#include <winrt/Microsoft.ReactNative.h>
#include <winrt/Windows.Foundation.Collections.h>
#include <winrt/Windows.Foundation.h>
#include "winrt/Microsoft.ReactNative.h"

#include "gtest/gtest.h"
#include "motifCpp/gTestAdapter.h"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
</ItemGroup>
<ItemGroup>
<ClInclude Include="$(MSBuildThisFileDirectory)Crash.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)ReactHandleHelper.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)JSValue.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)JSValueReader.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)JSValueTreeReader.h" />
Expand All @@ -23,6 +24,7 @@
<ClInclude Include="$(MSBuildThisFileDirectory)JSValueXaml.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)ModuleRegistration.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)NativeModules.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)ReactDispatcher.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)ReactNonAbiValue.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)ReactPropertyBag.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)ReactContext.h" />
Expand Down
73 changes: 61 additions & 12 deletions vnext/Microsoft.ReactNative.Cxx/NativeModules.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
// Licensed under the MIT License.

#pragma once
#include "winrt/Microsoft.ReactNative.h"
#include <winrt/Microsoft.ReactNative.h>
#include <winrt/Windows.Foundation.h>

#include "JSValueReader.h"
#include "JSValueWriter.h"
Expand Down Expand Up @@ -1108,29 +1109,77 @@ struct TurboModuleSpec {
}
};

// The default factory for the TModule.
// It wraps up the TModule into a ReactNonAbiValue to be passed through the ABI boundary.
template <class TModule>
inline std::tuple<winrt::Windows::Foundation::IInspectable, TModule *> MakeDefaultReactModuleWrapper() noexcept {
ReactNonAbiValue<TModule> moduleWrapper{std::in_place};
TModule *module = moduleWrapper.GetPtr();
return std::tuple<winrt::Windows::Foundation::IInspectable, TModule *>{std::move(moduleWrapper), module};
}

// The default factory for TModule inherited from enable_shared_from_this<T>.
// It wraps up the TModule into an std::shared_ptr before giving it to ReactNonAbiValue.
template <class TModule>
inline std::tuple<winrt::Windows::Foundation::IInspectable, TModule *>
MakeDefaultSharedPtrReactModuleWrapper() noexcept {
ReactNonAbiValue<std::shared_ptr<TModule>> moduleWrapper{std::in_place, std::make_shared<TModule>()};
TModule *module = moduleWrapper.GetPtr()->get();
return std::tuple<winrt::Windows::Foundation::IInspectable, TModule *>{std::move(moduleWrapper), module};
}

namespace Internal {
// Internal functions to test if type is inherited from std::enable_shared_from_this<T>.
template <class T>
std::true_type IsBaseOfTemplateTest(std::enable_shared_from_this<T> *);
std::false_type IsBaseOfTemplateTest(...);
} // namespace Internal

// Check if type T is inherited from std::enable_shared_form_this<U>.
// We support the scenario when the T and U are different types.
template <class T>
using IsEnabledSharedFromThisT = decltype(Internal::IsBaseOfTemplateTest((T *)nullptr));
template <class T>
inline constexpr bool IsEnabledSharedFromThisV = IsEnabledSharedFromThisT<T>::value;

// Default implementation of factory getter for a TModule type **not** inherited from std::enable_shared_form_this.
// For the custom implementation define GetReactModuleFactory with the last parameter to be 'int' (not 'int *').
template <class TModule, std::enable_if_t<!IsEnabledSharedFromThisV<TModule>, int> = 0>
inline constexpr auto GetReactModuleFactory(TModule * /*moduleNullPtr*/, int * /*useDefault*/) noexcept {
return &MakeDefaultReactModuleWrapper<TModule>;
}

// Default implementation of factory getter for a TModule type inherited from std::enable_shared_form_this.
// For the custom implementation define GetReactModuleFactory with the last parameter to be 'int' (not 'int *').
template <class TModule, std::enable_if_t<IsEnabledSharedFromThisV<TModule>, int> = 0>
inline constexpr auto GetReactModuleFactory(TModule * /*moduleNullPtr*/, int * /*useDefault*/) noexcept {
return &MakeDefaultSharedPtrReactModuleWrapper<TModule>;
}

// Type traits for TModule. It defines a factory to create the module and its ABI-safe wrapper.
template <class TModule>
struct ReactModuleTraits {
using FactoryType = std::tuple<winrt::Windows::Foundation::IInspectable, TModule *>() noexcept;
static constexpr FactoryType *Factory = GetReactModuleFactory((TModule *)nullptr, 0);
};

// Create a module provider for TModule type.
template <class TModule>
inline ReactModuleProvider MakeModuleProvider() noexcept {
return [](IReactModuleBuilder const &moduleBuilder) noexcept {
ReactNonAbiValue<TModule> moduleObject{std::in_place};
TModule *module = moduleObject.GetPtr();
auto [moduleWrapper, module] = ReactModuleTraits<TModule>::Factory();
ReactModuleBuilder builder{module, moduleBuilder};
GetReactModuleInfo(module, builder);
builder.CompleteRegistration();
return moduleObject;
return moduleWrapper;
};
}

// Create a module provider for TModule type that satisfies the TModuleSpec.
template <class TModule, class TModuleSpec>
inline ReactModuleProvider MakeTurboModuleProvider() noexcept {
TModuleSpec::template ValidateModule<TModule>();
return [](IReactModuleBuilder const &moduleBuilder) noexcept {
ReactNonAbiValue<TModule> moduleObject{std::in_place};
TModule *module = moduleObject.GetPtr();
ReactModuleBuilder builder{module, moduleBuilder};
GetReactModuleInfo(module, builder);
builder.CompleteRegistration();
return moduleObject;
};
return MakeModuleProvider<TModule>();
}

} // namespace winrt::Microsoft::ReactNative
Expand Down
7 changes: 6 additions & 1 deletion vnext/Microsoft.ReactNative.Cxx/ReactContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

#include <string_view>
#include "JSValueWriter.h"
#include "ReactDispatcher.h"
#include "ReactPropertyBag.h"

namespace winrt::Microsoft::ReactNative {
Expand All @@ -24,13 +25,17 @@ struct ReactContext {
}

explicit operator bool() const noexcept {
return static_cast<bool>(m_handle);
return m_handle ? true : false;
}

ReactPropertyBag Properties() const noexcept {
return ReactPropertyBag{m_handle.Properties()};
}

ReactDispatcher UIDispatcher() const noexcept {
return ReactDispatcher{m_handle.UIDispatcher()};
}

// Call methodName JS function of module with moduleName.
// args are either function arguments or a single lambda with 'IJSValueWriter const&' argument.
template <class... TArgs>
Expand Down
49 changes: 49 additions & 0 deletions vnext/Microsoft.ReactNative.Cxx/ReactDispatcher.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

#pragma once
#ifndef MICROSOFT_REACTNATIVE_REACTDISPATCHER
#define MICROSOFT_REACTNATIVE_REACTDISPATCHER

#include <winrt/Microsoft.ReactNative.h>
#include "ReactHandleHelper.h"

namespace winrt::Microsoft::ReactNative {

// Represents a dispatcher queue to invoke work item asynchronously.
// It wraps up the IReactDispatcher and adds convenience methods for
// working with C++ types.
struct ReactDispatcher {
ReactDispatcher(std::nullptr_t = nullptr) noexcept {}

explicit ReactDispatcher(IReactDispatcher const &handle) noexcept : m_handle{handle} {}

IReactDispatcher const &Handle() const noexcept {
return m_handle;
}

explicit operator bool() const noexcept {
return m_handle ? true : false;
}

void Post(ReactDispatcherCallback const &callback) const noexcept {
if (m_handle) {
m_handle.Post(callback);
}
}

bool HasThreadAccess() const noexcept {
return m_handle ? m_handle.HasThreadAccess() : false;
}

static ReactDispatcher CreateSerialDispatcher() noexcept {
return ReactDispatcher{ReactDispatcherHelper::CreateSerialDispatcher()};
}

private:
IReactDispatcher m_handle;
};

} // namespace winrt::Microsoft::ReactNative

#endif // MICROSOFT_REACTNATIVE_REACTDISPATCHER
67 changes: 67 additions & 0 deletions vnext/Microsoft.ReactNative.Cxx/ReactHandleHelper.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

#pragma once
#ifndef MICROSOFT_REACTNATIVE_REACTHANDLEHELPER
#define MICROSOFT_REACTNATIVE_REACTHANDLEHELPER

//
// Helper methods for types that have Handle() method that return
// an IInspectable-inherited value.
//

#include <winrt/Microsoft.ReactNative.h>
#include <type_traits>

namespace winrt::Microsoft::ReactNative {

namespace Internal {
template <class T>
auto TestHandle(int) -> decltype(std::declval<T>().Handle());
template <class>
auto TestHandle(int *) -> void;
} // namespace Internal

template <class T>
inline constexpr bool HasHandleV =
std::is_base_of_v<Windows::Foundation::IInspectable, std::decay_t<decltype(Internal::TestHandle<T>(0))>>;

// True if two types with Handle() have the same handle.
template <class T, std::enable_if_t<HasHandleV<T>, int> = 0>
inline bool operator==(T const &left, T const &right) noexcept {
return left.Handle() == right.Handle();
}

// True if two types with Handle() have different handles.
template <class T, std::enable_if_t<HasHandleV<T>, int> = 0>
inline bool operator!=(T const &left, T const &right) noexcept {
return !(left.Handle() == right.Handle());
}

// True if handle of left is null.
template <class T, std::enable_if_t<HasHandleV<T>, int> = 0>
inline bool operator==(T const &left, std::nullptr_t) noexcept {
return !static_cast<bool>(left.Handle());
}

// True if handle of left is not null.
template <class T, std::enable_if_t<HasHandleV<T>, int> = 0>
inline bool operator!=(T const &left, std::nullptr_t) noexcept {
return static_cast<bool>(left.Handle());
}

// True if handle of right is null.
template <class T, std::enable_if_t<HasHandleV<T>, int> = 0>
inline bool operator==(std::nullptr_t, T const &right) noexcept {
return !static_cast<bool>(right.Handle());
}

// True if handle of left is not null.
template <class T, std::enable_if_t<HasHandleV<T>, int> = 0>
inline bool operator!=(std::nullptr_t, T const &right) noexcept {
return static_cast<bool>(right.Handle());
}

} // namespace winrt::Microsoft::ReactNative

#endif // MICROSOFT_REACTNATIVE_REACTHANDLEHELPER
Loading