Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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": "ReactNotificationService to allow communications between native modules",
"packageName": "react-native-windows",
"email": "[email protected]",
"dependentChangeType": "patch",
"date": "2020-05-19T20:43:32.803Z"
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,18 @@ struct SampleModuleCppImpl {
DEBUG_OUTPUT("C++ Properties.Prop1:", *reactContext.Properties().Get(myProp1));
DEBUG_OUTPUT("C++ Properties.Prop2:", winrt::to_string(*reactContext.Properties().Get(myProp2)));

const ReactNotificationId<int> cppTimerNotification{L"SampleModuleCppImpl", L"TimerNotification"};
const ReactNotificationId<int> csTimerNotification{L"SampleModuleCS", L"TimerNotification"};

reactContext.Notifications().Subscribe(csTimerNotification, [
](winrt::Windows::Foundation::IInspectable const &, ReactNotificationArgs<int> const &args) noexcept {
DEBUG_OUTPUT("C++ module, C# timer:", *args.Data());
});

m_timer = winrt::Windows::System::Threading::ThreadPoolTimer::CreatePeriodicTimer(
[this](const winrt::Windows::System::Threading::ThreadPoolTimer) noexcept {
[ this, cppTimerNotification, notifications = reactContext.Notifications() ](
const winrt::Windows::System::Threading::ThreadPoolTimer) noexcept {
notifications.SendNotification(cppTimerNotification, m_timerCount);
TimedEvent(++m_timerCount);
if (m_timer && m_timerCount == 5) {
m_timer.Cancel();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,15 @@ public void Initialize(ReactContext reactContext)
Debug.WriteLine($"C# Properties.Prop1: {reactContext.Handle.Properties.Get(ReactPropertyBagHelper.GetName(null, "Prop1"))}");
Debug.WriteLine($"C# Properties.Prop2: {reactContext.Handle.Properties.Get(ReactPropertyBagHelper.GetName(null, "Prop2"))}");

var cppTimerNotification = ReactPropertyBagHelper.GetName(ReactPropertyBagHelper.GetNamespace("SampleModuleCppImpl"), "TimerNotification");
var csTimerNotification = ReactPropertyBagHelper.GetName(ReactPropertyBagHelper.GetNamespace("SampleModuleCS"), "TimerNotification");

reactContext.Handle.Notifications.Subscribe(cppTimerNotification, null,
(object sender, IReactNotificationArgs args) => Debug.WriteLine($"C# module, C++ timer:: {args.Data}"));

_timer = ThreadPoolTimer.CreatePeriodicTimer(new TimerElapsedHandler((timer) =>
{
reactContext.Handle.Notifications.SendNotification(csTimerNotification, null, _timerCount);
TimedEvent?.Invoke(++_timerCount);
if (_timerCount == 5)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
<ItemGroup>
<ClInclude Include="$(MSBuildThisFileDirectory)CppWinRTIncludes.h" />
<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 @@ -28,7 +29,9 @@
<ClInclude Include="$(MSBuildThisFileDirectory)ModuleRegistration.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)NamespaceRedirect.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)NativeModules.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)ReactDispatcher.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)ReactNonAbiValue.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)ReactNotificationService.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)ReactPropertyBag.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)ReactContext.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)ReactError.h" />
Expand Down
5 changes: 5 additions & 0 deletions vnext/Microsoft.ReactNative.Cxx/ReactContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include <CppWinRTIncludes.h>
#include <string_view>
#include "JSValueWriter.h"
#include "ReactNotificationService.h"
#include "ReactPropertyBag.h"

namespace winrt::Microsoft::ReactNative {
Expand All @@ -32,6 +33,10 @@ struct ReactContext {
return ReactPropertyBag{m_handle.Properties()};
}

ReactNotificationService Notifications() const noexcept {
return ReactNotificationService{m_handle.Notifications()};
}

// 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} {}
Copy link

@NikoAri NikoAri May 19, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

& [](start = 49, length = 2)

(nit) Since we are doing assignment anyways, wouldn't && be better here? #Resolved

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is the C++/WinRT thing. It always gives us const &.


In reply to: 427624661 [](ancestors = 427624661)


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

explicit operator bool() const noexcept {
return static_cast<bool>(m_handle);
Copy link
Member

@asklar asklar May 19, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

consider making this explicit by comparing against nullptr instead #Resolved

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will change it to code that C++/WinRT uses:
m_handle ? true : false;

Comparing with nullptr is more expensive as it involves calling a constructor with nullptr parameter and then comparing two objects.


In reply to: 427648694 [](ancestors = 427648694)

}

void Post(ReactDispatcherCallback const &callback) const noexcept {
if (m_handle) {
Copy link

@NikoAri NikoAri May 19, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

m_handle [](start = 8, length = 8)

(nit) can you add comment of why we would ever want this to be null? #Resolved

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This class supports move semantic. It can be null if its content is moved out, or nullptr is given at construction.


In reply to: 427625320 [](ancestors = 427625320)

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();
Copy link
Member

@asklar asklar May 19, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

consider not using the != operator, and instead use !(left.Handle() == right.Handle()) #Resolved

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed


In reply to: 427649165 [](ancestors = 427649165)

}

// 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