/*********************************************************************** THIS FILE IS AUTOMATICALLY GENERATED. DO NOT MODIFY DEVELOPER: Zihan Chen(vczh) ***********************************************************************/ #include "VlppWorkflowLibrary.h" /*********************************************************************** .\WFLIBRARYCPPHELPER.CPP ***********************************************************************/ namespace vl { namespace __vwsn { /*********************************************************************** CreateArray ***********************************************************************/ CreateArray::CreateArray() :list(IValueArray::Create()) { } CreateArray::CreateArray(Ptr _list) :list(_list) { } /*********************************************************************** CreateList ***********************************************************************/ CreateList::CreateList() :list(IValueList::Create()) { } CreateList::CreateList(Ptr _list) :list(_list) { } /*********************************************************************** CreateObservableList ***********************************************************************/ CreateObservableList::CreateObservableList() :list(IValueObservableList::Create()) { } CreateObservableList::CreateObservableList(Ptr _list) :list(_list) { } /*********************************************************************** CreateDictionary ***********************************************************************/ CreateDictionary::CreateDictionary() :dictionary(IValueDictionary::Create()) { } CreateDictionary::CreateDictionary(Ptr _dictionary) :dictionary(_dictionary) { } } } /*********************************************************************** .\WFLIBRARYPREDEFINED.CPP ***********************************************************************/ namespace vl { using namespace collections; namespace reflection { namespace description { /*********************************************************************** CoroutineResult ***********************************************************************/ Value CoroutineResult::GetResult() { return result; } void CoroutineResult::SetResult(const Value& value) { result = value; } Ptr CoroutineResult::GetFailure() { return failure; } void CoroutineResult::SetFailure(Ptr value) { failure = value; } /*********************************************************************** EnumerableCoroutine ***********************************************************************/ class CoroutineEnumerator : public Object, public virtual EnumerableCoroutine::IImpl, public Description { protected: EnumerableCoroutine::Creator creator; Ptr coroutine; Value current; vint index = -1; Ptr joining; public: CoroutineEnumerator(const EnumerableCoroutine::Creator& _creator) :creator(_creator) { } Value GetCurrent()override { return current; } vint GetIndex()override { return index; } bool Next()override { if (!coroutine) { coroutine = creator(this); } while (coroutine->GetStatus() == CoroutineStatus::Waiting) { if (joining) { if (joining->Next()) { current = joining->GetCurrent(); index++; return true; } else { joining = nullptr; } } coroutine->Resume(true, nullptr); if (coroutine->GetStatus() != CoroutineStatus::Waiting) { break; } if (!joining) { index++; return true; } } return false; } void OnYield(const Value& value)override { current = value; joining = nullptr; } void OnJoin(Ptr value)override { if (!value) { throw Exception(L"Cannot join a null collection."); } current = Value(); joining = value->CreateEnumerator(); } }; class CoroutineEnumerable : public Object, public virtual IValueEnumerable, public Description { protected: EnumerableCoroutine::Creator creator; public: CoroutineEnumerable(const EnumerableCoroutine::Creator& _creator) :creator(_creator) { } Ptr CreateEnumerator()override { return Ptr(new CoroutineEnumerator(creator)); } }; void EnumerableCoroutine::YieldAndPause(IImpl* impl, const Value& value) { impl->OnYield(value); } void EnumerableCoroutine::JoinAndPause(IImpl* impl, Ptr value) { impl->OnJoin(value); } void EnumerableCoroutine::ReturnAndExit(IImpl* impl) { } Ptr EnumerableCoroutine::Create(const Creator& creator) { return Ptr(new CoroutineEnumerable(creator)); } /*********************************************************************** AsyncContext ***********************************************************************/ AsyncContext::AsyncContext(const Value& _context) :context(_context) { } AsyncContext::~AsyncContext() { } bool AsyncContext::IsCancelled() { SPIN_LOCK(lock) { return cancelled; } CHECK_FAIL(L"Not reachable"); } bool AsyncContext::Cancel() { SPIN_LOCK(lock) { if (cancelled) return false; cancelled = true; return true; } CHECK_FAIL(L"Not reachable"); } const description::Value& AsyncContext::GetContext() { SPIN_LOCK(lock) { return context; } CHECK_FAIL(L"Not reachable"); } void AsyncContext::SetContext(const description::Value& value) { SPIN_LOCK(lock) { context = value; } } /*********************************************************************** DelayAsync ***********************************************************************/ class DelayAsync : public Object, public virtual IAsync, public Description { protected: SpinLock lock; vint milliseconds; AsyncStatus status = AsyncStatus::Ready; public: DelayAsync(vint _milliseconds) :milliseconds(_milliseconds) { } AsyncStatus GetStatus()override { return status; } bool Execute(const Func)>& _callback, Ptr context)override { SPIN_LOCK(lock) { if (status != AsyncStatus::Ready) return false; status = AsyncStatus::Executing; IAsyncScheduler::GetSchedulerForCurrentThread()->DelayExecute([async = Ptr(this), callback = _callback]() { if (callback) { callback(nullptr); } }, milliseconds); } return true; } }; Ptr IAsync::Delay(vint milliseconds) { return Ptr(new DelayAsync(milliseconds)); } /*********************************************************************** FutureAndPromiseAsync ***********************************************************************/ class FutureAndPromiseAsync : public virtual IFuture, public virtual IPromise, public Description { public: SpinLock lock; AsyncStatus status = AsyncStatus::Ready; Ptr cr; Func)> callback; void ExecuteCallbackAndClear() { status = AsyncStatus::Stopped; if (callback) { callback(cr); } cr = nullptr; callback = {}; } template bool Send(F f) { SPIN_LOCK(lock) { if (status == AsyncStatus::Stopped || cr) return false; cr = Ptr(new CoroutineResult); f(); if (status == AsyncStatus::Executing) { ExecuteCallbackAndClear(); } } return true; } AsyncStatus GetStatus()override { return status; } bool Execute(const Func)>& _callback, Ptr context)override { SPIN_LOCK(lock) { if (status != AsyncStatus::Ready) return false; callback = _callback; if (cr) { ExecuteCallbackAndClear(); } else { status = AsyncStatus::Executing; } } return true; } Ptr GetPromise()override { return Ptr(this); } bool SendResult(const Value& result)override { return Send([=, this]() { cr->SetResult(result); }); } bool SendFailure(Ptr failure)override { return Send([=, this]() { cr->SetFailure(failure); }); } }; Ptr IFuture::Create() { return Ptr(new FutureAndPromiseAsync); } /*********************************************************************** IAsyncScheduler ***********************************************************************/ class AsyncSchedulerMap { public: Dictionary> schedulers; Ptr defaultScheduler; }; AsyncSchedulerMap* asyncSchedulerMap = nullptr; SpinLock asyncSchedulerLock; #define ENSURE_ASYNC_SCHEDULER_MAP\ if (!asyncSchedulerMap) asyncSchedulerMap = new AsyncSchedulerMap; #define DISPOSE_ASYNC_SCHEDULER_MAP_IF_NECESSARY\ if (asyncSchedulerMap->schedulers.Count() == 0 && !asyncSchedulerMap->defaultScheduler)\ {\ delete asyncSchedulerMap;\ asyncSchedulerMap = nullptr;\ }\ void IAsyncScheduler::RegisterDefaultScheduler(Ptr scheduler) { SPIN_LOCK(asyncSchedulerLock) { ENSURE_ASYNC_SCHEDULER_MAP CHECK_ERROR(!asyncSchedulerMap->defaultScheduler, L"IAsyncScheduler::RegisterDefaultScheduler()#A default scheduler has already been registered."); asyncSchedulerMap->defaultScheduler = scheduler; } } void IAsyncScheduler::RegisterSchedulerForCurrentThread(Ptr scheduler) { SPIN_LOCK(asyncSchedulerLock) { ENSURE_ASYNC_SCHEDULER_MAP CHECK_ERROR(!asyncSchedulerMap->schedulers.Keys().Contains(Thread::GetCurrentThreadId()), L"IAsyncScheduler::RegisterDefaultScheduler()#A scheduler for this thread has already been registered."); asyncSchedulerMap->schedulers.Add(Thread::GetCurrentThreadId(), scheduler); } } Ptr IAsyncScheduler::UnregisterDefaultScheduler() { Ptr scheduler; SPIN_LOCK(asyncSchedulerLock) { if (asyncSchedulerMap) { scheduler = asyncSchedulerMap->defaultScheduler; asyncSchedulerMap->defaultScheduler = nullptr; DISPOSE_ASYNC_SCHEDULER_MAP_IF_NECESSARY } } return scheduler; } Ptr IAsyncScheduler::UnregisterSchedulerForCurrentThread() { Ptr scheduler; SPIN_LOCK(asyncSchedulerLock) { if (asyncSchedulerMap) { vint index = asyncSchedulerMap->schedulers.Keys().IndexOf(Thread::GetCurrentThreadId()); if (index != -1) { scheduler = asyncSchedulerMap->schedulers.Values()[index]; asyncSchedulerMap->schedulers.Remove(Thread::GetCurrentThreadId()); } DISPOSE_ASYNC_SCHEDULER_MAP_IF_NECESSARY } } return scheduler; } #undef ENSURE_ASYNC_SCHEDULER_MAP #undef DISPOSE_ASYNC_SCHEDULER_MAP_IF_NECESSARY Ptr IAsyncScheduler::GetSchedulerForCurrentThread() { Ptr scheduler; SPIN_LOCK(asyncSchedulerLock) { CHECK_ERROR(asyncSchedulerMap != nullptr, L"IAsyncScheduler::GetSchedulerForCurrentThread()#There is no scheduler registered for the current thread."); vint index = asyncSchedulerMap->schedulers.Keys().IndexOf(Thread::GetCurrentThreadId()); if (index != -1) { scheduler = asyncSchedulerMap->schedulers.Values()[index]; } else if (asyncSchedulerMap->defaultScheduler) { scheduler = asyncSchedulerMap->defaultScheduler; } else { CHECK_FAIL(L"IAsyncScheduler::GetSchedulerForCurrentThread()#There is no scheduler registered for the current thread."); } } return scheduler; } /*********************************************************************** AsyncCoroutine ***********************************************************************/ class CoroutineAsync : public Object, public virtual AsyncCoroutine::IImpl, public Description { protected: Ptr coroutine; AsyncCoroutine::Creator creator; Ptr scheduler; Func)> callback; Ptr context; Value result; public: CoroutineAsync(AsyncCoroutine::Creator _creator) :creator(_creator) { } AsyncStatus GetStatus()override { if (!coroutine) { return AsyncStatus::Ready; } else if (coroutine->GetStatus() != CoroutineStatus::Stopped) { return AsyncStatus::Executing; } else { return AsyncStatus::Stopped; } } bool Execute(const Func)>& _callback, Ptr _context)override { if (coroutine) return false; scheduler = IAsyncScheduler::GetSchedulerForCurrentThread(); callback = _callback; context = _context; coroutine = creator(this); OnContinue(nullptr); return true; } Ptr GetScheduler()override { return scheduler; } Ptr GetContext()override { if (!context) { context = Ptr(new AsyncContext); } return context; } void OnContinue(Ptr output)override { scheduler->Execute([async = Ptr(this), output]() { async->coroutine->Resume(false, output); if (async->coroutine->GetStatus() == CoroutineStatus::Stopped && async->callback) { auto result = Ptr(new CoroutineResult); if (async->coroutine->GetFailure()) { result->SetFailure(async->coroutine->GetFailure()); } else { result->SetResult(async->result); } async->callback(result); } }); } void OnReturn(const Value& value)override { result = value; } }; void AsyncCoroutine::AwaitAndRead(IImpl* impl, Ptr value) { value->Execute([async = Ptr(impl)](auto output) { async->OnContinue(output); }, impl->GetContext()); } void AsyncCoroutine::ReturnAndExit(IImpl* impl, const Value& value) { impl->OnReturn(value); } Ptr AsyncCoroutine::QueryContext(IImpl* impl) { return impl->GetContext(); } Ptr AsyncCoroutine::Create(const Creator& creator) { return Ptr(new CoroutineAsync(creator)); } void AsyncCoroutine::CreateAndRun(const Creator& creator) { Ptr(new CoroutineAsync(creator))->Execute( [](Ptr cr) { if (cr->GetFailure()) { #pragma push_macro("GetMessage") #if defined GetMessage #undef GetMessage #endif throw Exception(cr->GetFailure()->GetMessage()); #pragma pop_macro("GetMessage") } }, nullptr); } /*********************************************************************** StateMachine ***********************************************************************/ void StateMachine::ResumeStateMachine() { Ptr previousResult; while (true) { if (stateMachineCoroutine == nullptr) { if (!stateMachineInitialized) { throw Exception(L"The state machine has not been initialized."); } if (stateMachineStopped) { throw Exception(L"The state machine has been stopped."); } stateMachineStopped = true; if (previousResult) { if (auto failure = previousResult->GetFailure()) { throw Exception(failure->GetMessage()); } } break; } else if (stateMachineCoroutine->GetStatus() != CoroutineStatus::Stopped) { auto currentCoroutine = stateMachineCoroutine; currentCoroutine->Resume(false, previousResult); if (stateMachineCoroutine == currentCoroutine) { // wait for input break; } else if (currentCoroutine->GetStatus() == CoroutineStatus::Stopped) { // leave a state machine previousResult = Ptr(new CoroutineResult); if (auto failure = currentCoroutine->GetFailure()) { previousResult->SetFailure(failure); } } else { // enter a state machine } } } } StateMachine::StateMachine() { } StateMachine::~StateMachine() { FinalizeAggregation(); } CoroutineStatus StateMachine::GetStateMachineStatus() { if (stateMachineStopped) { return CoroutineStatus::Stopped; } else if (stateMachineCoroutine) { if (stateMachineCoroutine->GetStatus() == CoroutineStatus::Waiting) { return CoroutineStatus::Waiting; } else { return CoroutineStatus::Executing; } } else { return CoroutineStatus::Waiting; } } /*********************************************************************** Sys ***********************************************************************/ namespace system_sys { class ReverseEnumerable : public Object, public IValueEnumerable { protected: Ptr list; class Enumerator : public Object, public IValueEnumerator { protected: Ptr list; vint index; public: Enumerator(Ptr _list) :list(_list), index(_list->GetCount()) { } Value GetCurrent() { return list->Get(index); } vint GetIndex() { return list->GetCount() - 1 - index; } bool Next() { if (index <= 0) return false; index--; return true; } }; public: ReverseEnumerable(Ptr _list) :list(_list) { } Ptr CreateEnumerator()override { return Ptr(new Enumerator(list)); } }; } DateTime Sys::GetLocalTime() { return DateTime::LocalTime(); } DateTime Sys::GetUtcTime() { return DateTime::UtcTime(); } DateTime Sys::ToLocalTime(DateTime dt) { return dt.ToLocalTime(); } DateTime Sys::ToUtcTime(DateTime dt) { return dt.ToUtcTime(); } DateTime Sys::Forward(DateTime dt, vuint64_t milliseconds) { return dt.Forward(milliseconds); } DateTime Sys::Backward(DateTime dt, vuint64_t milliseconds) { return dt.Backward(milliseconds); } DateTime Sys::CreateDateTime(vint year, vint month, vint day) { return DateTime::FromDateTime(year, month, day); } DateTime Sys::CreateDateTime(vint year, vint month, vint day, vint hour, vint minute, vint second, vint milliseconds) { return DateTime::FromDateTime(year, month, day, hour, minute, second, milliseconds); } Ptr Sys::ReverseEnumerable(Ptr value) { auto list = value.Cast(); if (!list) { list = IValueList::Create(GetLazyList(value)); } return Ptr(new system_sys::ReverseEnumerable(list)); } #define DEFINE_COMPARE(TYPE)\ vint Sys::Compare(TYPE a, TYPE b)\ {\ auto result = a <=> b;\ if (result < 0) return -1;\ if (result > 0) return 1;\ return 0;\ }\ REFLECTION_PREDEFINED_PRIMITIVE_TYPES(DEFINE_COMPARE) DEFINE_COMPARE(DateTime) #undef DEFINE_COMPARE /*********************************************************************** Math ***********************************************************************/ #define DEFINE_MINMAX(TYPE)\ TYPE Math::Min(TYPE a, TYPE b)\ {\ return Sys::Compare(a, b) < 0 ? a : b;\ }\ TYPE Math::Max(TYPE a, TYPE b)\ {\ return Sys::Compare(a, b) > 0 ? a : b;\ }\ REFLECTION_PREDEFINED_PRIMITIVE_TYPES(DEFINE_MINMAX) DEFINE_MINMAX(DateTime) #undef DEFINE_MINMAX /*********************************************************************** Localization ***********************************************************************/ Locale Localization::Invariant() { return Locale::Invariant(); } Locale Localization::System() { return Locale::SystemDefault(); } Locale Localization::User() { return Locale::UserDefault(); } collections::LazyList Localization::Locales() { auto result = Ptr(new List); Locale::Enumerate(*result.Obj()); return result; } collections::LazyList Localization::GetShortDateFormats(Locale locale) { auto result = Ptr(new List); locale.GetShortDateFormats(*result.Obj()); return result; } collections::LazyList Localization::GetLongDateFormats(Locale locale) { auto result = Ptr(new List); locale.GetLongDateFormats(*result.Obj()); return result; } collections::LazyList Localization::GetYearMonthDateFormats(Locale locale) { auto result = Ptr(new List); locale.GetYearMonthDateFormats(*result.Obj()); return result; } collections::LazyList Localization::GetLongTimeFormats(Locale locale) { auto result = Ptr(new List); locale.GetLongTimeFormats(*result.Obj()); return result; } collections::LazyList Localization::GetShortTimeFormats(Locale locale) { auto result = Ptr(new List); locale.GetShortTimeFormats(*result.Obj()); return result; } WString Localization::GetShortDayOfWeekName(Locale locale, vint dayOfWeek) { return locale.GetShortDayOfWeekName(dayOfWeek); } WString Localization::GetLongDayOfWeekName(Locale locale, vint dayOfWeek) { return locale.GetLongDayOfWeekName(dayOfWeek); } WString Localization::GetShortMonthName(Locale locale, vint month) { return locale.GetShortMonthName(month); } WString Localization::GetLongMonthName(Locale locale, vint month) { return locale.GetLongMonthName(month); } WString Localization::FormatDate(Locale locale, const WString& format, DateTime date) { return locale.FormatDate(format, date); } WString Localization::FormatTime(Locale locale, const WString& format, DateTime date) { return locale.FormatTime(format, date); } WString Localization::FormatNumber(Locale locale, const WString& number) { return locale.FormatNumber(number); } WString Localization::FormatCurrency(Locale locale, const WString& number) { return locale.FormatCurrency(number); } /*********************************************************************** Versioning ***********************************************************************/ Versioning::Versioning() { } Versioning::~Versioning() { } vint Versioning::AllocateVersion() { return ++version; } vint Versioning::GetVersion() { return version; } } } } /*********************************************************************** .\WFLIBRARYREFLECTION.CPP ***********************************************************************/ #include #include namespace vl { using namespace collections; using namespace regex; namespace reflection { namespace description { /*********************************************************************** TypeName ***********************************************************************/ #ifndef VCZH_DEBUG_NO_REFLECTION IMPL_TYPE_INFO_RENAME(vl::reflection::description::Sys, system::Sys) IMPL_TYPE_INFO_RENAME(vl::reflection::description::Math, system::Math) IMPL_TYPE_INFO_RENAME(vl::reflection::description::Localization, system::Localization) IMPL_TYPE_INFO_RENAME(vl::reflection::description::CoroutineStatus, system::CoroutineStatus) IMPL_TYPE_INFO_RENAME(vl::reflection::description::CoroutineResult, system::CoroutineResult) IMPL_TYPE_INFO_RENAME(vl::reflection::description::ICoroutine, system::Coroutine) IMPL_TYPE_INFO_RENAME(vl::reflection::description::EnumerableCoroutine::IImpl, system::EnumerableCoroutine::IImpl) IMPL_TYPE_INFO_RENAME(vl::reflection::description::EnumerableCoroutine, system::EnumerableCoroutine) IMPL_TYPE_INFO_RENAME(vl::reflection::description::AsyncStatus, system::AsyncStatus) IMPL_TYPE_INFO_RENAME(vl::reflection::description::AsyncContext, system::AsyncContext) IMPL_TYPE_INFO_RENAME(vl::reflection::description::IAsync, system::Async) IMPL_TYPE_INFO_RENAME(vl::reflection::description::IPromise, system::Promise) IMPL_TYPE_INFO_RENAME(vl::reflection::description::IFuture, system::Future) IMPL_TYPE_INFO_RENAME(vl::reflection::description::IAsyncScheduler, system::AsyncScheduler) IMPL_TYPE_INFO_RENAME(vl::reflection::description::AsyncCoroutine::IImpl, system::AsyncCoroutine::IImpl) IMPL_TYPE_INFO_RENAME(vl::reflection::description::AsyncCoroutine, system::AsyncCoroutine) IMPL_TYPE_INFO_RENAME(vl::reflection::description::StateMachine, system::StateMachine) IMPL_TYPE_INFO_RENAME(vl::reflection::description::Versioning, system::Versioning) IMPL_TYPE_INFO_RENAME(vl::rpc_controller::RpcObjectReference, system::RpcObjectReference) IMPL_TYPE_INFO_RENAME(vl::rpc_controller::RpcException, system::RpcException) IMPL_TYPE_INFO_RENAME(vl::rpc_controller::RpcByvalReturnValue, system::RpcByvalReturnValue) IMPL_TYPE_INFO_RENAME(vl::rpc_controller::IRpcSerializer, system::IRpcSerializer) IMPL_TYPE_INFO_RENAME(vl::rpc_controller::IRpcListOps, system::IRpcListOps) IMPL_TYPE_INFO_RENAME(vl::rpc_controller::IRpcListEventOps, system::IRpcListEventOps) IMPL_TYPE_INFO_RENAME(vl::rpc_controller::IRpcObjectOps, system::IRpcObjectOps) IMPL_TYPE_INFO_RENAME(vl::rpc_controller::IRpcObjectEventOps, system::IRpcObjectEventOps) IMPL_TYPE_INFO_RENAME(vl::rpc_controller::IRpcOperations, system::IRpcOperations) IMPL_TYPE_INFO_RENAME(vl::rpc_controller::IRpcDispatcher, system::IRpcDispatcher) IMPL_TYPE_INFO_RENAME(vl::rpc_controller::IRpcController, system::IRpcController) IMPL_TYPE_INFO_RENAME(vl::rpc_controller::IRpcLifecycle, system::IRpcLifecycle) IMPL_TYPE_INFO_RENAME(vl::rpc_controller::IRpcWrapperBase, system::IRpcWrapperBase) IMPL_TYPE_INFO_RENAME(vl::rpc_controller::RpcByrefEnumerator, system::RpcByrefEnumerator) IMPL_TYPE_INFO_RENAME(vl::rpc_controller::RpcByrefEnumerable, system::RpcByrefEnumerable) IMPL_TYPE_INFO_RENAME(vl::rpc_controller::RpcByrefReadonlyList, system::RpcByrefReadonlyList) IMPL_TYPE_INFO_RENAME(vl::rpc_controller::RpcByrefList, system::RpcByrefList) IMPL_TYPE_INFO_RENAME(vl::rpc_controller::RpcByrefArray, system::RpcByrefArray) IMPL_TYPE_INFO_RENAME(vl::rpc_controller::RpcByrefObservableList, system::RpcByrefObservableList) IMPL_TYPE_INFO_RENAME(vl::rpc_controller::RpcByrefDictionary, system::RpcByrefDictionary) IMPL_TYPE_INFO_RENAME(vl::__vwsn::att_cpp_File, system::workflow_attributes::att_cpp_File) IMPL_TYPE_INFO_RENAME(vl::__vwsn::att_cpp_UserImpl, system::workflow_attributes::att_cpp_UserImpl) IMPL_TYPE_INFO_RENAME(vl::__vwsn::att_cpp_Private, system::workflow_attributes::att_cpp_Private) IMPL_TYPE_INFO_RENAME(vl::__vwsn::att_cpp_Protected, system::workflow_attributes::att_cpp_Protected) IMPL_TYPE_INFO_RENAME(vl::__vwsn::att_cpp_Friend, system::workflow_attributes::att_cpp_Friend) IMPL_TYPE_INFO_RENAME(vl::__vwsn::att_rpc_Interface, system::workflow_attributes::att_rpc_Interface) IMPL_TYPE_INFO_RENAME(vl::__vwsn::att_rpc_Ctor, system::workflow_attributes::att_rpc_Ctor) IMPL_TYPE_INFO_RENAME(vl::__vwsn::att_rpc_Byval, system::workflow_attributes::att_rpc_Byval) IMPL_TYPE_INFO_RENAME(vl::__vwsn::att_rpc_Byref, system::workflow_attributes::att_rpc_Byref) IMPL_TYPE_INFO_RENAME(vl::__vwsn::att_rpc_Cached, system::workflow_attributes::att_rpc_Cached) IMPL_TYPE_INFO_RENAME(vl::__vwsn::att_rpc_Dynamic, system::workflow_attributes::att_rpc_Dynamic) IMPL_TYPE_INFO_RENAME(vl::__vwsn::att_rpc_IdString, system::workflow_attributes::att_rpc_IdString) IMPL_TYPE_INFO_RENAME(vl::__vwsn::att_rpc_IdNumber, system::workflow_attributes::att_rpc_IdNumber) #endif /*********************************************************************** WfLoadLibraryTypes ***********************************************************************/ #ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA #define _ , BEGIN_STRUCT_MEMBER(vl::__vwsn::att_cpp_File) STRUCT_MEMBER(argument) END_STRUCT_MEMBER(vl::__vwsn::att_cpp_File) BEGIN_STRUCT_MEMBER(vl::__vwsn::att_cpp_UserImpl) END_STRUCT_MEMBER(vl::__vwsn::att_cpp_UserImpl) BEGIN_STRUCT_MEMBER(vl::__vwsn::att_cpp_Private) END_STRUCT_MEMBER(vl::__vwsn::att_cpp_Private) BEGIN_STRUCT_MEMBER(vl::__vwsn::att_cpp_Protected) END_STRUCT_MEMBER(vl::__vwsn::att_cpp_Protected) BEGIN_STRUCT_MEMBER(vl::__vwsn::att_cpp_Friend) STRUCT_MEMBER(argument) END_STRUCT_MEMBER(vl::__vwsn::att_cpp_Friend) BEGIN_STRUCT_MEMBER(vl::__vwsn::att_rpc_Interface) END_STRUCT_MEMBER(vl::__vwsn::att_rpc_Interface) BEGIN_STRUCT_MEMBER(vl::__vwsn::att_rpc_Ctor) END_STRUCT_MEMBER(vl::__vwsn::att_rpc_Ctor) BEGIN_STRUCT_MEMBER(vl::__vwsn::att_rpc_Byval) END_STRUCT_MEMBER(vl::__vwsn::att_rpc_Byval) BEGIN_STRUCT_MEMBER(vl::__vwsn::att_rpc_Byref) END_STRUCT_MEMBER(vl::__vwsn::att_rpc_Byref) BEGIN_STRUCT_MEMBER(vl::__vwsn::att_rpc_Cached) END_STRUCT_MEMBER(vl::__vwsn::att_rpc_Cached) BEGIN_STRUCT_MEMBER(vl::__vwsn::att_rpc_Dynamic) END_STRUCT_MEMBER(vl::__vwsn::att_rpc_Dynamic) BEGIN_STRUCT_MEMBER(vl::__vwsn::att_rpc_IdString) STRUCT_MEMBER(argument) END_STRUCT_MEMBER(vl::__vwsn::att_rpc_IdString) BEGIN_STRUCT_MEMBER(vl::__vwsn::att_rpc_IdNumber) STRUCT_MEMBER(argument) END_STRUCT_MEMBER(vl::__vwsn::att_rpc_IdNumber) BEGIN_STRUCT_MEMBER(vl::rpc_controller::RpcObjectReference) STRUCT_MEMBER(clientId) STRUCT_MEMBER(objectId) STRUCT_MEMBER(typeId) END_STRUCT_MEMBER(vl::rpc_controller::RpcObjectReference) BEGIN_STRUCT_MEMBER(vl::rpc_controller::RpcException) STRUCT_MEMBER(message) END_STRUCT_MEMBER(vl::rpc_controller::RpcException) BEGIN_CLASS_MEMBER(vl::rpc_controller::RpcByvalReturnValue) CLASS_MEMBER_CONSTRUCTOR(Ptr(), NO_PARAMETER) CLASS_MEMBER_FIELD(value) CLASS_MEMBER_FIELD(slot) END_CLASS_MEMBER(vl::rpc_controller::RpcByvalReturnValue) BEGIN_INTERFACE_MEMBER(vl::rpc_controller::IRpcSerializer) CLASS_MEMBER_METHOD(Serialize, { L"value" }) CLASS_MEMBER_METHOD(Deserialize, { L"value" }) END_INTERFACE_MEMBER(vl::rpc_controller::IRpcSerializer) BEGIN_INTERFACE_MEMBER(vl::rpc_controller::IRpcListOps) CLASS_MEMBER_METHOD(EnumCreate, { L"ref" }) CLASS_MEMBER_METHOD(EnumNext, { L"enumerator" }) CLASS_MEMBER_METHOD(EnumGetCurrent, { L"enumerator" }) CLASS_MEMBER_METHOD(ListGetCount, { L"ref" }) CLASS_MEMBER_METHOD(ListGet, { L"ref" _ L"index" }) CLASS_MEMBER_METHOD(ListSet, { L"ref" _ L"index" _ L"value" }) CLASS_MEMBER_METHOD(ListAdd, { L"ref" _ L"value" }) CLASS_MEMBER_METHOD(ListInsert, { L"ref" _ L"index" _ L"value" }) CLASS_MEMBER_METHOD(ListRemoveAt, { L"ref" _ L"index" }) CLASS_MEMBER_METHOD(ListClear, { L"ref" }) CLASS_MEMBER_METHOD(ListContains, { L"ref" _ L"value" }) CLASS_MEMBER_METHOD(ListIndexOf, { L"ref" _ L"value" }) CLASS_MEMBER_METHOD(DictGetCount, { L"ref" }) CLASS_MEMBER_METHOD(DictGet, { L"ref" _ L"key" }) CLASS_MEMBER_METHOD(DictSet, { L"ref" _ L"key" _ L"value" }) CLASS_MEMBER_METHOD(DictRemove, { L"ref" _ L"key" }) CLASS_MEMBER_METHOD(DictClear, { L"ref" }) CLASS_MEMBER_METHOD(DictContainsKey, { L"ref" _ L"key" }) CLASS_MEMBER_METHOD(DictGetKeys, { L"ref" }) CLASS_MEMBER_METHOD(DictGetValues, { L"ref" }) END_INTERFACE_MEMBER(vl::rpc_controller::IRpcListOps) BEGIN_INTERFACE_MEMBER(vl::rpc_controller::IRpcListEventOps) CLASS_MEMBER_METHOD(OnItemChanged, { L"ref" _ L"index" _ L"oldCount" _ L"newCount" }) END_INTERFACE_MEMBER(vl::rpc_controller::IRpcListEventOps) BEGIN_INTERFACE_MEMBER(vl::rpc_controller::IRpcObjectOps) CLASS_MEMBER_METHOD(InvokeMethod, { L"ref" _ L"methodId" _ L"arguments" }) CLASS_MEMBER_METHOD(EndInvokeMethod, { L"slot" }) CLASS_MEMBER_METHOD(ObjectHold, { L"ref" _ L"remoteClientId" _ L"hold" }) CLASS_MEMBER_METHOD(RegisterService, { L"typeId" _ L"service" }) END_INTERFACE_MEMBER(vl::rpc_controller::IRpcObjectOps) BEGIN_INTERFACE_MEMBER(vl::rpc_controller::IRpcObjectEventOps) CLASS_MEMBER_METHOD(InvokeEvent, { L"ref" _ L"eventId" _ L"arguments" }) END_INTERFACE_MEMBER(vl::rpc_controller::IRpcObjectEventOps) BEGIN_INTERFACE_MEMBER_NOPROXY(vl::rpc_controller::IRpcOperations) CLASS_MEMBER_PROPERTY_READONLY_FAST(ListOps) CLASS_MEMBER_PROPERTY_READONLY_FAST(ObjectOps) CLASS_MEMBER_PROPERTY_READONLY_FAST(ListEventOps) CLASS_MEMBER_PROPERTY_READONLY_FAST(ObjectEventOps) END_INTERFACE_MEMBER(vl::rpc_controller::IRpcOperations) BEGIN_INTERFACE_MEMBER_NOPROXY(vl::rpc_controller::IRpcDispatcher) CLASS_MEMBER_METHOD(Finalize, NO_PARAMETER) CLASS_MEMBER_METHOD(IsRegisteredService, { L"ref" }) CLASS_MEMBER_METHOD(RegisterService, { L"typeId" _ L"ref" }) CLASS_MEMBER_METHOD(RequestService, { L"typeId" }) CLASS_MEMBER_METHOD(BroadcastFromClient_ListEventOps, { L"selfClientId" }) CLASS_MEMBER_METHOD(BroadcastFromClient_ObjectEventOps, { L"selfClientId" }) CLASS_MEMBER_METHOD(SendToClient_ListOps, { L"targetClientId" }) CLASS_MEMBER_METHOD(SendToClient_ObjectOps, { L"targetClientId" }) END_INTERFACE_MEMBER(vl::rpc_controller::IRpcDispatcher) BEGIN_INTERFACE_MEMBER_NOPROXY(vl::rpc_controller::IRpcController) CLASS_MEMBER_BASE(vl::rpc_controller::IRpcOperations) CLASS_MEMBER_METHOD(Finalize, NO_PARAMETER) CLASS_MEMBER_METHOD(SetEventSuppressedFlag, { L"ref" _ L"eventId" _ L"suppressed" }) CLASS_MEMBER_METHOD(GetEventSuppressedFlag, { L"ref" _ L"eventId" }) CLASS_MEMBER_METHOD(SetItemChangedSuppressedFlag, { L"ref" _ L"suppressed" }) CLASS_MEMBER_METHOD(GetItemChangedSuppressedFlag, { L"ref" }) END_INTERFACE_MEMBER(vl::rpc_controller::IRpcController) BEGIN_INTERFACE_MEMBER_NOPROXY(vl::rpc_controller::IRpcLifecycle) CLASS_MEMBER_METHOD(Finalize, NO_PARAMETER) CLASS_MEMBER_PROPERTY_READONLY_FAST(ClientId) CLASS_MEMBER_PROPERTY_READONLY_FAST(Dispatcher) CLASS_MEMBER_PROPERTY_READONLY_FAST(Controller) CLASS_MEMBER_PROPERTY_READONLY_FAST(Serializer) CLASS_MEMBER_METHOD(RefToPtr, { L"ref" }) CLASS_MEMBER_METHOD(PtrToRef, { L"obj" }) CLASS_MEMBER_METHOD(LocalObjectHold, { L"ref" _ L"remoteClientId" }) CLASS_MEMBER_METHOD(LocalObjectUnhold, { L"ref" _ L"remoteClientId" }) CLASS_MEMBER_METHOD(RegisterService, { L"fullName" _ L"service" }) CLASS_MEMBER_METHOD(RequestService, { L"fullName" }) CLASS_MEMBER_STATIC_EXTERNALMETHOD(RpcBoxByref, { L"trivial" _ L"lc" }, vl::rpc_controller::RpcObjectReference(*)(vl::Ptr, vl::rpc_controller::IRpcLifecycle*), vl::rpc_controller::RpcBoxByref) CLASS_MEMBER_STATIC_EXTERNALMETHOD(RpcUnboxByref, { L"serializable" _ L"lc" }, vl::Ptr(*)(vl::rpc_controller::RpcObjectReference, vl::rpc_controller::IRpcLifecycle*), vl::rpc_controller::RpcUnboxByref) CLASS_MEMBER_STATIC_EXTERNALMETHOD(RpcCopyByval, { L"trivial" _ L"lc" }, Value(*)(const Value&, vl::rpc_controller::IRpcLifecycle*), vl::rpc_controller::RpcCopyByval) CLASS_MEMBER_STATIC_EXTERNALMETHOD(RpcBoxByval, { L"trivial" _ L"lc" }, Value(*)(const Value&, vl::rpc_controller::IRpcLifecycle*), vl::rpc_controller::RpcBoxByval) CLASS_MEMBER_STATIC_EXTERNALMETHOD(RpcUnboxByval, { L"serializable" _ L"lc" }, vl::Ptr(*)(const Value&, vl::rpc_controller::IRpcLifecycle*), vl::rpc_controller::RpcUnboxByval) CLASS_MEMBER_STATIC_EXTERNALMETHOD(ReadMethodException, { L"value" }, void(*)(const Value&), vl::rpc_controller::ReadMethodException) CLASS_MEMBER_STATIC_EXTERNALMETHOD(ReadEventException, { L"exceptions" }, void(*)(vl::rpc_controller::RpcEventExceptionMap), vl::rpc_controller::ReadEventException) CLASS_MEMBER_STATIC_EXTERNALMETHOD(JsonSerializePredefinedTypes, { L"value" _ L"rpcjson_Serialize" }, vl::Ptr(*)(const Value&, const vl::rpc_controller::RpcJsonSerializeCallback&), vl::rpc_controller::JsonSerializePredefinedTypes) CLASS_MEMBER_STATIC_EXTERNALMETHOD(JsonDeserializePredefinedTypes, { L"value" _ L"rpcjson_Deserialize" }, Value(*)(const Value&, const vl::rpc_controller::RpcJsonDeserializeCallback&), vl::rpc_controller::JsonDeserializePredefinedTypes) END_INTERFACE_MEMBER(vl::rpc_controller::IRpcLifecycle) BEGIN_INTERFACE_MEMBER(vl::rpc_controller::IRpcWrapperBase) CLASS_MEMBER_METHOD(DisconnectFromLifecycle, NO_PARAMETER) END_INTERFACE_MEMBER(vl::rpc_controller::IRpcWrapperBase) BEGIN_CLASS_MEMBER(vl::rpc_controller::RpcByrefEnumerator) CLASS_MEMBER_BASE(vl::reflection::description::IValueEnumerator) CLASS_MEMBER_BASE(vl::rpc_controller::IRpcWrapperBase) END_CLASS_MEMBER(vl::rpc_controller::RpcByrefEnumerator) BEGIN_CLASS_MEMBER(vl::rpc_controller::RpcByrefEnumerable) CLASS_MEMBER_BASE(vl::reflection::description::IValueEnumerable) CLASS_MEMBER_BASE(vl::rpc_controller::IRpcWrapperBase) END_CLASS_MEMBER(vl::rpc_controller::RpcByrefEnumerable) BEGIN_CLASS_MEMBER(vl::rpc_controller::RpcByrefReadonlyList) CLASS_MEMBER_BASE(vl::reflection::description::IValueReadonlyList) CLASS_MEMBER_BASE(vl::rpc_controller::IRpcWrapperBase) END_CLASS_MEMBER(vl::rpc_controller::RpcByrefReadonlyList) BEGIN_CLASS_MEMBER(vl::rpc_controller::RpcByrefList) CLASS_MEMBER_BASE(vl::rpc_controller::RpcByrefReadonlyList) CLASS_MEMBER_BASE(vl::reflection::description::IValueList) END_CLASS_MEMBER(vl::rpc_controller::RpcByrefList) BEGIN_CLASS_MEMBER(vl::rpc_controller::RpcByrefArray) CLASS_MEMBER_BASE(vl::reflection::description::IValueArray) CLASS_MEMBER_BASE(vl::rpc_controller::IRpcWrapperBase) END_CLASS_MEMBER(vl::rpc_controller::RpcByrefArray) BEGIN_CLASS_MEMBER(vl::rpc_controller::RpcByrefObservableList) CLASS_MEMBER_BASE(vl::reflection::description::IValueObservableList) CLASS_MEMBER_BASE(vl::rpc_controller::IRpcWrapperBase) END_CLASS_MEMBER(vl::rpc_controller::RpcByrefObservableList) BEGIN_CLASS_MEMBER(vl::rpc_controller::RpcByrefDictionary) CLASS_MEMBER_BASE(vl::reflection::description::IValueDictionary) CLASS_MEMBER_BASE(vl::rpc_controller::IRpcWrapperBase) END_CLASS_MEMBER(vl::rpc_controller::RpcByrefDictionary) BEGIN_CLASS_MEMBER(Sys) CLASS_MEMBER_STATIC_METHOD(Int32ToInt, { L"value" }) CLASS_MEMBER_STATIC_METHOD(Int64ToInt, { L"value" }) CLASS_MEMBER_STATIC_METHOD(IntToInt32, { L"value" }) CLASS_MEMBER_STATIC_METHOD(IntToInt64, { L"value" }) CLASS_MEMBER_STATIC_METHOD(UInt32ToUInt, { L"value" }) CLASS_MEMBER_STATIC_METHOD(UInt64ToUInt, { L"value" }) CLASS_MEMBER_STATIC_METHOD(UIntToUInt32, { L"value" }) CLASS_MEMBER_STATIC_METHOD(UIntToUInt64, { L"value" }) CLASS_MEMBER_STATIC_METHOD(Len, { L"value" }) CLASS_MEMBER_STATIC_METHOD(Left, { L"value" _ L"length" }) CLASS_MEMBER_STATIC_METHOD(Right, { L"value" _ L"length" }) CLASS_MEMBER_STATIC_METHOD(Mid, { L"value" _ L"start" _ L"length" }) CLASS_MEMBER_STATIC_METHOD(Find, { L"value" _ L"substr" }) CLASS_MEMBER_STATIC_METHOD(UCase, { L"value" }) CLASS_MEMBER_STATIC_METHOD(LCase, { L"value" }) CLASS_MEMBER_STATIC_METHOD(LoremIpsumTitle, { L"bestLength" }) CLASS_MEMBER_STATIC_METHOD(LoremIpsumSentence, { L"bestLength" }) CLASS_MEMBER_STATIC_METHOD(LoremIpsumParagraph, { L"bestLength" }) CLASS_MEMBER_STATIC_METHOD(ReverseEnumerable, { L"value" }) #pragma push_macro("CompareString") #if defined CompareString #undef CompareString #endif #define DEFINE_COMPARE(TYPE) CLASS_MEMBER_STATIC_METHOD_OVERLOAD(Compare, PROTECT_PARAMETERS({L"a" _ L"b"}), vint(*)(TYPE, TYPE)) REFLECTION_PREDEFINED_PRIMITIVE_TYPES(DEFINE_COMPARE) DEFINE_COMPARE(DateTime) #undef DEFINE_COMPARE #pragma pop_macro("CompareString") CLASS_MEMBER_STATIC_METHOD(GetLocalTime, NO_PARAMETER) CLASS_MEMBER_STATIC_METHOD(GetUtcTime, NO_PARAMETER) CLASS_MEMBER_STATIC_METHOD(ToLocalTime, { L"dt" }) CLASS_MEMBER_STATIC_METHOD(ToUtcTime, { L"dt" }) CLASS_MEMBER_STATIC_METHOD(Forward, { L"dt" _ L"milliseconds" }) CLASS_MEMBER_STATIC_METHOD(Backward, { L"dt" _ L"milliseconds" }) CLASS_MEMBER_STATIC_METHOD_OVERLOAD(CreateDateTime, {L"year" _ L"month" _ L"day" }, DateTime(*)(vint, vint, vint)) CLASS_MEMBER_STATIC_METHOD_OVERLOAD(CreateDateTime, { L"year" _ L"month" _ L"day" _ L"hour" _ L"minute" _ L"second" _ L"milliseconds" }, DateTime(*)(vint, vint, vint, vint, vint, vint, vint)) END_CLASS_MEMBER(Sys) BEGIN_CLASS_MEMBER(Math) CLASS_MEMBER_STATIC_METHOD(Pi, NO_PARAMETER) CLASS_MEMBER_STATIC_METHOD_OVERLOAD(Abs, { L"value" }, vint8_t(*)(vint8_t)) CLASS_MEMBER_STATIC_METHOD_OVERLOAD(Abs, { L"value" }, vint16_t(*)(vint16_t)) CLASS_MEMBER_STATIC_METHOD_OVERLOAD(Abs, { L"value" }, vint32_t(*)(vint32_t)) CLASS_MEMBER_STATIC_METHOD_OVERLOAD(Abs, { L"value" }, vint64_t(*)(vint64_t)) CLASS_MEMBER_STATIC_METHOD_OVERLOAD(Abs, { L"value" }, float(*)(float)) CLASS_MEMBER_STATIC_METHOD_OVERLOAD(Abs, { L"value" }, double(*)(double)) #define DEFINE_MINMAX(TYPE)\ CLASS_MEMBER_STATIC_METHOD_OVERLOAD(Min, PROTECT_PARAMETERS({L"a" _ L"b"}), TYPE(*)(TYPE, TYPE))\ CLASS_MEMBER_STATIC_METHOD_OVERLOAD(Max, PROTECT_PARAMETERS({L"a" _ L"b"}), TYPE(*)(TYPE, TYPE))\ REFLECTION_PREDEFINED_PRIMITIVE_TYPES(DEFINE_MINMAX) DEFINE_MINMAX(DateTime) #undef DEFINE_MINMAX CLASS_MEMBER_STATIC_METHOD(Sin, { L"value" }) CLASS_MEMBER_STATIC_METHOD(Cos, { L"value" }) CLASS_MEMBER_STATIC_METHOD(Tan, { L"value" }) CLASS_MEMBER_STATIC_METHOD(ASin, { L"value" }) CLASS_MEMBER_STATIC_METHOD(ACos, { L"value" }) CLASS_MEMBER_STATIC_METHOD(ATan, { L"value" }) CLASS_MEMBER_STATIC_METHOD(ATan2, { L"x" _ L"y" }) CLASS_MEMBER_STATIC_METHOD(Exp, { L"value" }) CLASS_MEMBER_STATIC_METHOD(LogN, { L"value" }) CLASS_MEMBER_STATIC_METHOD(Log10, { L"value" }) CLASS_MEMBER_STATIC_METHOD(Log, { L"value" _ L"base" }) CLASS_MEMBER_STATIC_METHOD(Pow, { L"value" _ L"power" }) CLASS_MEMBER_STATIC_METHOD(Ceil, { L"value" }) CLASS_MEMBER_STATIC_METHOD(Floor, { L"value" }) CLASS_MEMBER_STATIC_METHOD(Round, { L"value" }) CLASS_MEMBER_STATIC_METHOD(Trunc, { L"value" }) END_CLASS_MEMBER(Math) BEGIN_CLASS_MEMBER(Localization) CLASS_MEMBER_STATIC_METHOD(Invariant, NO_PARAMETER) CLASS_MEMBER_STATIC_METHOD(System, NO_PARAMETER) CLASS_MEMBER_STATIC_METHOD(User, NO_PARAMETER) CLASS_MEMBER_STATIC_METHOD(Locales, NO_PARAMETER) CLASS_MEMBER_STATIC_METHOD(GetShortDateFormats, { L"locale" }) CLASS_MEMBER_STATIC_METHOD(GetLongDateFormats, { L"locale" }) CLASS_MEMBER_STATIC_METHOD(GetYearMonthDateFormats, { L"locale" }) CLASS_MEMBER_STATIC_METHOD(GetLongTimeFormats, { L"locale" }) CLASS_MEMBER_STATIC_METHOD(GetShortTimeFormats, { L"locale" }) CLASS_MEMBER_STATIC_METHOD(GetShortDayOfWeekName, { L"locale" _ L"dayOfWeek" }) CLASS_MEMBER_STATIC_METHOD(GetLongDayOfWeekName, { L"locale" _ L"dayOfWeek" }) CLASS_MEMBER_STATIC_METHOD(GetShortMonthName, { L"locale" _ L"month" }) CLASS_MEMBER_STATIC_METHOD(GetLongMonthName, { L"locale" _ L"month" }) CLASS_MEMBER_STATIC_METHOD(FormatDate, { L"locale" _ L"format" _ L"date" }) CLASS_MEMBER_STATIC_METHOD(FormatTime, { L"locale" _ L"format" _ L"date" }) CLASS_MEMBER_STATIC_METHOD(FormatNumber, { L"locale" _ L"number" }) CLASS_MEMBER_STATIC_METHOD(FormatCurrency, { L"locale" _ L"number" }) END_CLASS_MEMBER(Localization) BEGIN_ENUM_ITEM(CoroutineStatus) ENUM_CLASS_ITEM(Waiting) ENUM_CLASS_ITEM(Executing) ENUM_CLASS_ITEM(Stopped) END_ENUM_ITEM(CoroutineStatus) BEGIN_INTERFACE_MEMBER(ICoroutine) CLASS_MEMBER_METHOD(Resume, { L"raiseException" _ L"output" }) CLASS_MEMBER_PROPERTY_READONLY_FAST(Failure) CLASS_MEMBER_PROPERTY_READONLY_FAST(Status) END_INTERFACE_MEMBER(ICoroutine) BEGIN_CLASS_MEMBER(CoroutineResult) CLASS_MEMBER_CONSTRUCTOR(Ptr(), NO_PARAMETER) CLASS_MEMBER_PROPERTY_FAST(Result) CLASS_MEMBER_PROPERTY_FAST(Failure) END_CLASS_MEMBER(CoroutineResult) BEGIN_INTERFACE_MEMBER_NOPROXY(EnumerableCoroutine::IImpl) CLASS_MEMBER_BASE(IValueEnumerator) END_INTERFACE_MEMBER(EnumerableCoroutine::IImpl) BEGIN_CLASS_MEMBER(EnumerableCoroutine) CLASS_MEMBER_STATIC_METHOD(YieldAndPause, { L"impl" _ L"value" }) CLASS_MEMBER_STATIC_METHOD(JoinAndPause, { L"impl" _ L"value" }) CLASS_MEMBER_STATIC_METHOD(ReturnAndExit, { L"impl" }) CLASS_MEMBER_STATIC_METHOD(Create, { L"creator" }) END_CLASS_MEMBER(EnumerableCoroutine) BEGIN_ENUM_ITEM(AsyncStatus) ENUM_CLASS_ITEM(Ready) ENUM_CLASS_ITEM(Executing) ENUM_CLASS_ITEM(Stopped) END_ENUM_ITEM(AsyncStatus) BEGIN_CLASS_MEMBER(AsyncContext) CLASS_MEMBER_CONSTRUCTOR(Ptr(const Value&), {L"context"}) CLASS_MEMBER_METHOD(IsCancelled, NO_PARAMETER) CLASS_MEMBER_METHOD(Cancel, NO_PARAMETER) CLASS_MEMBER_PROPERTY_FAST(Context) END_CLASS_MEMBER(AsyncContext) BEGIN_INTERFACE_MEMBER(IAsync) CLASS_MEMBER_PROPERTY_READONLY_FAST(Status) CLASS_MEMBER_METHOD(Execute, { L"callback" _ L"context" }) CLASS_MEMBER_STATIC_METHOD(Delay, { L"milliseconds" }) END_INTERFACE_MEMBER(IAsync) BEGIN_INTERFACE_MEMBER_NOPROXY(IPromise) CLASS_MEMBER_METHOD(SendResult, { L"result" }) CLASS_MEMBER_METHOD(SendFailure, { L"failure" }) END_INTERFACE_MEMBER(IPromise) BEGIN_INTERFACE_MEMBER_NOPROXY(IFuture) CLASS_MEMBER_BASE(IAsync) CLASS_MEMBER_BASE(IPromise) CLASS_MEMBER_PROPERTY_READONLY_FAST(Promise) CLASS_MEMBER_STATIC_METHOD(Create, NO_PARAMETER) END_INTERFACE_MEMBER(IFuture) BEGIN_INTERFACE_MEMBER_NOPROXY(IAsyncScheduler) CLASS_MEMBER_METHOD(Execute, { L"callback" }) CLASS_MEMBER_METHOD(ExecuteInBackground, { L"callback" }) CLASS_MEMBER_METHOD(DelayExecute, { L"callback" _ L"milliseconds" }) CLASS_MEMBER_STATIC_METHOD(GetSchedulerForCurrentThread, NO_PARAMETER) END_INTERFACE_MEMBER(IAsyncScheduler) BEGIN_INTERFACE_MEMBER_NOPROXY(AsyncCoroutine::IImpl) CLASS_MEMBER_BASE(IAsync) END_INTERFACE_MEMBER(AsyncCoroutine::IImpl) BEGIN_CLASS_MEMBER(AsyncCoroutine) CLASS_MEMBER_STATIC_METHOD(AwaitAndRead, { L"impl" _ L"value" }) CLASS_MEMBER_STATIC_METHOD(ReturnAndExit, { L"impl" _ L"value"}) CLASS_MEMBER_STATIC_METHOD(QueryContext, { L"impl" }) CLASS_MEMBER_STATIC_METHOD(Create, { L"creator" }) CLASS_MEMBER_STATIC_METHOD(CreateAndRun, { L"creator" }) END_CLASS_MEMBER(AsyncCoroutine) BEGIN_CLASS_MEMBER(StateMachine) CLASS_MEMBER_FIELD(stateMachineInitialized) CLASS_MEMBER_FIELD(stateMachineStopped) CLASS_MEMBER_FIELD(stateMachineInput) CLASS_MEMBER_FIELD(stateMachineCoroutine) CLASS_MEMBER_CONSTRUCTOR(Ptr(), NO_PARAMETER) CLASS_MEMBER_METHOD(ResumeStateMachine, NO_PARAMETER) CLASS_MEMBER_PROPERTY_READONLY_FAST(StateMachineStatus) END_CLASS_MEMBER(StateMachine) BEGIN_CLASS_MEMBER(Versioning) CLASS_MEMBER_CONSTRUCTOR(Ptr(), NO_PARAMETER) CLASS_MEMBER_METHOD(AllocateVersion, NO_PARAMETER) CLASS_MEMBER_PROPERTY_READONLY_FAST(Version) END_CLASS_MEMBER(Versioning) #undef _ class WfLibraryTypeLoader : public Object, public ITypeLoader { public: void Load(ITypeManager* manager)override { WORKFLOW_LIBRARY_TYPES(ADD_TYPE_INFO) } void Unload(ITypeManager* manager)override { } }; #endif bool WfLoadLibraryTypes() { #ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA ITypeManager* manager = GetGlobalTypeManager(); if (manager) { auto loader = Ptr(new WfLibraryTypeLoader); return manager->AddTypeLoader(loader); } #endif return false; } } } } /*********************************************************************** .\RPC\WFLIBRARYRPC.CPP ***********************************************************************/ namespace vl { namespace rpc_controller { using namespace reflection::description; Value BoxRpcObjectReference(RpcObjectReference ref) { return Value::From(Ptr(new IValueType::TypedBox(ref)), nullptr); } Value BoxRpcException(RpcException exception) { return Value::From(Ptr(new IValueType::TypedBox(exception)), nullptr); } RpcEventExceptionMap CreateRpcEventExceptionMap() { return IValueDictionary::Create(); } void MergeRpcEventExceptionMap(RpcEventExceptionMap target, RpcEventExceptionMap source) { if (!source) return; auto keys = source->GetKeys(); for (vint i = 0; i < keys->GetCount(); i++) { auto key = keys->Get(i); target->Set(key, source->Get(key)); } } Value BoxRpcEventExceptionMap(RpcEventExceptionMap exceptions) { return exceptions ? BoxValue(exceptions) : Value(); } RpcEventExceptionMap UnboxRpcEventExceptionMap(const Value& value) { return value.IsNull() ? nullptr : UnboxValue(value); } } } /*********************************************************************** .\RPC\WFLIBRARYRPCCONTROLLER.CPP ***********************************************************************/ namespace vl { namespace rpc_controller { using namespace collections; /*********************************************************************** * RpcControllerDefault ***********************************************************************/ RpcControllerDefault::RpcControllerDefault() { } RpcControllerDefault::~RpcControllerDefault() { } void RpcControllerDefault::Register(Ptr _objectCallback, Ptr _eventCallback, Ptr _listCallback, Ptr _listEventCallback) { objectCallback = _objectCallback; eventCallback = _eventCallback; listCallback = _listCallback; listEventCallback = _listEventCallback; } IRpcListOps* RpcControllerDefault::GetListOps() { return listCallback.Obj(); } IRpcObjectOps* RpcControllerDefault::GetObjectOps() { return objectCallback.Obj(); } IRpcListEventOps* RpcControllerDefault::GetListEventOps() { return listEventCallback.Obj(); } IRpcObjectEventOps* RpcControllerDefault::GetObjectEventOps() { return eventCallback.Obj(); } void RpcControllerDefault::Finalize() { } template void RpcControllerDefault::SetSuppressedFlag(Dictionary& flags, const TKey& key, bool suppressed) { #define ERROR_MESSAGE_PREFIX L"vl::rpc_controller::RpcControllerDefault::SetSuppressedFlag(collections::Dictionary&, const TKey&, bool)#" auto index = flags.Keys().IndexOf(key); if (suppressed) { if (index == -1) { flags.Add(key, 1); } else { flags.Set(key, flags.Values()[index] + 1); } } else { CHECK_ERROR(index != -1, ERROR_MESSAGE_PREFIX L"Suppression counter is not set."); auto count = flags.Values()[index] - 1; CHECK_ERROR(count >= 0, ERROR_MESSAGE_PREFIX L"Suppression counter is negative."); if (count == 0) { flags.Remove(key); } else { flags.Set(key, count); } } #undef ERROR_MESSAGE_PREFIX } template bool RpcControllerDefault::GetSuppressedFlag(const Dictionary& flags, const TKey& key) { auto index = flags.Keys().IndexOf(key); return index != -1 && flags.Values()[index] > 0; } void RpcControllerDefault::SetEventSuppressedFlag(RpcObjectReference ref, vint eventId, bool suppressed) { SetSuppressedFlag(eventSuppressedFlags, { ref,eventId }, suppressed); } bool RpcControllerDefault::GetEventSuppressedFlag(RpcObjectReference ref, vint eventId) { return GetSuppressedFlag(eventSuppressedFlags, { ref,eventId }); } void RpcControllerDefault::SetItemChangedSuppressedFlag(RpcObjectReference ref, bool suppressed) { SetSuppressedFlag(itemChangedSuppressedFlags, ref, suppressed); } bool RpcControllerDefault::GetItemChangedSuppressedFlag(RpcObjectReference ref) { return GetSuppressedFlag(itemChangedSuppressedFlags, ref); } } } /*********************************************************************** .\RPC\WFLIBRARYRPCJSON.CPP ***********************************************************************/ namespace vl { namespace rpc_controller { using namespace collections; using namespace glr::json; using namespace reflection; using namespace reflection::description; namespace { Ptr CreateJsonLiteral(JsonLiteralValue value) { auto node = Ptr(new JsonLiteral); node->value = value; return node; } Ptr CreateJsonString(const WString& value) { auto node = Ptr(new JsonString); node->content.value = value; return node; } Ptr CreateJsonNumber(const WString& value) { auto node = Ptr(new JsonNumber); node->content.value = value; return node; } Ptr CreateJsonArray() { return Ptr(new JsonArray); } Ptr CreateJsonObject() { return Ptr(new JsonObject); } void AddJsonObjectField(Ptr object, const WString& name, Ptr value) { auto field = Ptr(new JsonObjectField); field->name.value = name; field->value = value; object->fields.Add(field); } Ptr GetJsonObjectField(Ptr object, const WString& name) { for (auto field : object->fields) { if (field->name.value == name) { return field->value; } } auto message = L"JSON object field not found: " + name; CHECK_FAIL(message.Buffer()); } Ptr FindJsonObjectField(Ptr object, const WString& name) { for (auto field : object->fields) { if (field->name.value == name) { return field->value; } } return nullptr; } WString GetJsonString(Ptr node) { auto stringNode = node.Cast(); CHECK_ERROR(stringNode, L"JSON string is expected."); return stringNode->content.value; } WString GetJsonNumber(Ptr node) { auto numberNode = node.Cast(); CHECK_ERROR(numberNode, L"JSON number is expected."); return numberNode->content.value; } Ptr CreateUnknownTuple(const WString& keyword, Ptr value) { auto array = CreateJsonArray(); array->items.Add(CreateJsonString(keyword)); array->items.Add(value); return Ptr(array); } template bool TrySerializeNumberPrimitive(const Value& value, const WString& keyword, Ptr& result) { auto primitive = __vwsn::UnboxWeak>(value); if (primitive) { result = CreateUnknownTuple(keyword, CreateJsonNumber(__vwsn::ToString(primitive.Value()))); return true; } return false; } template bool TrySerializeStringPrimitive(const Value& value, const WString& keyword, Ptr& result) { auto primitive = __vwsn::UnboxWeak>(value); if (primitive) { result = CreateUnknownTuple(keyword, CreateJsonString(__vwsn::ToString(primitive.Value()))); return true; } return false; } Ptr SerializeCollection(const WString& keyword, Ptr enumerable, const RpcJsonSerializeCallback& rpcjson_Serialize) { auto object = CreateJsonObject(); AddJsonObjectField(object, WString::Unmanaged(L"$"), CreateJsonString(keyword)); auto values = CreateJsonArray(); auto enumerator = enumerable->CreateEnumerator(); while (enumerator->Next()) { values->items.Add(rpcjson_Serialize(enumerator->GetCurrent())); } AddJsonObjectField(object, WString::Unmanaged(L"values"), values); return Ptr(object); } Ptr SerializeMap(Ptr dictionary, const RpcJsonSerializeCallback& rpcjson_Serialize) { auto object = CreateJsonObject(); AddJsonObjectField(object, WString::Unmanaged(L"$"), CreateJsonString(WString::Unmanaged(L"map"))); auto values = CreateJsonArray(); auto keys = dictionary->GetKeys(); for (vint i = 0; i < keys->GetCount(); i++) { auto key = keys->Get(i); auto pair = CreateJsonArray(); pair->items.Add(rpcjson_Serialize(key)); pair->items.Add(rpcjson_Serialize(dictionary->Get(key))); values->items.Add(pair); } AddJsonObjectField(object, WString::Unmanaged(L"values"), values); return Ptr(object); } Ptr TrySerializeCollectionTypes(const Value& value, const RpcJsonSerializeCallback& rpcjson_Serialize) { if (auto observableList = __vwsn::UnboxWeak>(value)) { return SerializeCollection(WString::Unmanaged(L"oblist"), observableList, rpcjson_Serialize); } if (auto dictionary = __vwsn::UnboxWeak>(value)) { return SerializeMap(dictionary, rpcjson_Serialize); } if (auto readonlyDictionary = __vwsn::UnboxWeak>(value)) { return SerializeMap(readonlyDictionary, rpcjson_Serialize); } if (auto list = __vwsn::UnboxWeak>(value)) { return SerializeCollection(WString::Unmanaged(L"list"), list, rpcjson_Serialize); } if (auto readonlyList = __vwsn::UnboxWeak>(value)) { return SerializeCollection(WString::Unmanaged(L"list"), readonlyList, rpcjson_Serialize); } if (auto enumerable = __vwsn::UnboxWeak>(value)) { return SerializeCollection(WString::Unmanaged(L"list"), enumerable, rpcjson_Serialize); } return nullptr; } Ptr TrySerializeRpcTypes(const Value& value) { if (auto ref = __vwsn::UnboxWeak>(value)) { auto object = CreateJsonObject(); AddJsonObjectField(object, WString::Unmanaged(L"$"), CreateJsonString(WString::Unmanaged(L"system::RpcObjectReference"))); AddJsonObjectField(object, WString::Unmanaged(L"clientId"), CreateJsonNumber(__vwsn::ToString(ref.Value().clientId))); AddJsonObjectField(object, WString::Unmanaged(L"objectId"), CreateJsonNumber(__vwsn::ToString(ref.Value().objectId))); AddJsonObjectField(object, WString::Unmanaged(L"typeId"), CreateJsonNumber(__vwsn::ToString(ref.Value().typeId))); return Ptr(object); } if (auto exception = __vwsn::UnboxWeak>(value)) { auto object = CreateJsonObject(); AddJsonObjectField(object, WString::Unmanaged(L"$"), CreateJsonString(WString::Unmanaged(L"system::RpcException"))); AddJsonObjectField(object, WString::Unmanaged(L"message"), CreateJsonString(exception.Value().message)); return Ptr(object); } return nullptr; } Value DeserializeList(Ptr object, bool observable, const RpcJsonDeserializeCallback& rpcjson_Deserialize) { auto values = GetJsonObjectField(object, WString::Unmanaged(L"values")).Cast(); CHECK_ERROR(values, L"JSON array is expected."); if (observable) { auto result = IValueObservableList::Create(); for (auto item : values->items) { result->Add(rpcjson_Deserialize(item)); } return BoxValue(result); } else { auto result = IValueList::Create(); for (auto item : values->items) { result->Add(rpcjson_Deserialize(item)); } return BoxValue(result); } } Value DeserializeMap(Ptr object, const RpcJsonDeserializeCallback& rpcjson_Deserialize) { auto values = GetJsonObjectField(object, WString::Unmanaged(L"values")).Cast(); CHECK_ERROR(values, L"JSON array is expected."); auto result = IValueDictionary::Create(); for (auto item : values->items) { auto pair = item.Cast(); CHECK_ERROR(pair, L"JSON array is expected."); result->Set(rpcjson_Deserialize(pair->items[0]), rpcjson_Deserialize(pair->items[1])); } return BoxValue(result); } Value TryDeserializeRpcTypes(Ptr object, const WString& keyword) { if (keyword == L"system::RpcObjectReference") { return BoxRpcObjectReference(RpcObjectReference{ __vwsn::Parse(GetJsonNumber(GetJsonObjectField(object, WString::Unmanaged(L"clientId")))), __vwsn::Parse(GetJsonNumber(GetJsonObjectField(object, WString::Unmanaged(L"objectId")))), __vwsn::Parse(GetJsonNumber(GetJsonObjectField(object, WString::Unmanaged(L"typeId")))), }); } if (keyword == L"system::RpcException") { return BoxRpcException(RpcException{ GetJsonString(GetJsonObjectField(object, WString::Unmanaged(L"message"))), }); } return {}; } } Ptr JsonSerializePredefinedTypes(const Value& value, const RpcJsonSerializeCallback& rpcjson_Serialize) { if (value.IsNull()) { return CreateJsonLiteral(JsonLiteralValue::Null); } if (auto primitive = __vwsn::UnboxWeak>(value)) { return CreateJsonLiteral(primitive.Value() ? JsonLiteralValue::True : JsonLiteralValue::False); } if (auto primitive = __vwsn::UnboxWeak>(value)) { return CreateJsonString(primitive.Value()); } Ptr result; if (TrySerializeNumberPrimitive(value, WString::Unmanaged(L"UInt8"), result)) return result; if (TrySerializeNumberPrimitive(value, WString::Unmanaged(L"UInt16"), result)) return result; if (TrySerializeNumberPrimitive(value, WString::Unmanaged(L"UInt32"), result)) return result; if (TrySerializeNumberPrimitive(value, WString::Unmanaged(L"UInt64"), result)) return result; if (TrySerializeNumberPrimitive(value, WString::Unmanaged(L"Int8"), result)) return result; if (TrySerializeNumberPrimitive(value, WString::Unmanaged(L"Int16"), result)) return result; if (TrySerializeNumberPrimitive(value, WString::Unmanaged(L"Int32"), result)) return result; if (TrySerializeNumberPrimitive(value, WString::Unmanaged(L"Int64"), result)) return result; if (TrySerializeNumberPrimitive(value, WString::Unmanaged(L"Single"), result)) return result; if (TrySerializeNumberPrimitive(value, WString::Unmanaged(L"Double"), result)) return result; if (TrySerializeStringPrimitive(value, WString::Unmanaged(L"Char"), result)) return result; if (TrySerializeStringPrimitive(value, WString::Unmanaged(L"DateTime"), result)) return result; if (TrySerializeStringPrimitive(value, WString::Unmanaged(L"Locale"), result)) return result; if (auto rpcType = TrySerializeRpcTypes(value)) { return rpcType; } if (auto collection = TrySerializeCollectionTypes(value, rpcjson_Serialize)) { return collection; } CHECK_FAIL(L"Unsupported RPC JSON serialization value."); } Value JsonDeserializePredefinedTypes(const Value& value, const RpcJsonDeserializeCallback& rpcjson_Deserialize) { if (value.IsNull()) { return {}; } auto node = UnboxValue>(value); if (!node) { return {}; } if (auto literal = node.Cast()) { switch (literal->value) { case JsonLiteralValue::Null: return {}; case JsonLiteralValue::True: return BoxValue(true); case JsonLiteralValue::False: return BoxValue(false); default: CHECK_FAIL(L"Unsupported JSON literal."); } } if (auto stringNode = node.Cast()) { return BoxValue(stringNode->content.value); } if (auto numberNode = node.Cast()) { return BoxValue(numberNode->content.value); } if (auto array = node.Cast()) { if (array->items.Count() == 2) { if (auto keywordNode = array->items[0].Cast()) { auto keyword = keywordNode->content.value; auto item = array->items[1]; if (keyword == L"UInt8") return BoxValue(__vwsn::Parse(GetJsonNumber(item))); if (keyword == L"UInt16") return BoxValue(__vwsn::Parse(GetJsonNumber(item))); if (keyword == L"UInt32") return BoxValue(__vwsn::Parse(GetJsonNumber(item))); if (keyword == L"UInt64") return BoxValue(__vwsn::Parse(GetJsonNumber(item))); if (keyword == L"Int8") return BoxValue(__vwsn::Parse(GetJsonNumber(item))); if (keyword == L"Int16") return BoxValue(__vwsn::Parse(GetJsonNumber(item))); if (keyword == L"Int32") return BoxValue(__vwsn::Parse(GetJsonNumber(item))); if (keyword == L"Int64") return BoxValue(__vwsn::Parse(GetJsonNumber(item))); if (keyword == L"Single") return BoxValue(__vwsn::Parse(GetJsonNumber(item))); if (keyword == L"Double") return BoxValue(__vwsn::Parse(GetJsonNumber(item))); if (keyword == L"Char") return BoxValue(__vwsn::Parse(GetJsonString(item))); if (keyword == L"DateTime") return BoxValue(__vwsn::Parse(GetJsonString(item))); if (keyword == L"Locale") return BoxValue(__vwsn::Parse(GetJsonString(item))); } } auto result = IValueList::Create(); for (auto item : array->items) { result->Add(rpcjson_Deserialize(item)); } return BoxValue(result); } if (auto object = node.Cast()) { if (auto keywordNode = FindJsonObjectField(object, WString::Unmanaged(L"$"))) { auto keyword = GetJsonString(keywordNode); if (auto value = TryDeserializeRpcTypes(object, keyword); !value.IsNull()) return value; if (keyword == L"list") return DeserializeList(object, false, rpcjson_Deserialize); if (keyword == L"oblist") return DeserializeList(object, true, rpcjson_Deserialize); if (keyword == L"map") return DeserializeMap(object, rpcjson_Deserialize); CHECK_FAIL(L"Unknown RPC JSON object schema."); } auto result = IValueDictionary::Create(); for (auto field : object->fields) { result->Set(BoxValue(field->name.value), rpcjson_Deserialize(field->value)); } return BoxValue(result); } CHECK_FAIL(L"Unsupported RPC JSON node."); } } } /*********************************************************************** .\RPC\WFLIBRARYRPCLIFECYCLE.CPP ***********************************************************************/ namespace vl { namespace rpc_controller { using namespace reflection; using namespace reflection::description; using namespace collections; namespace { bool IsRpcWrapperObject(DescriptableObject* obj) { if (!obj) return false; if (dynamic_cast(obj)) return true; #ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA if (auto typeDescriptor = obj->GetTypeDescriptor()) { if (auto wrapperType = GetTypeDescriptor(WString::Unmanaged(L"system::IRpcWrapperBase"))) { return typeDescriptor->CanConvertTo(wrapperType); } } #endif return false; } } WString RpcLifecycleBase::InternalProperty_LocalObjectTracker = WString::Unmanaged(L"RpcLocalObjectTracker"); WString RpcLifecycleBase::InternalProperty_WrapperTracker = WString::Unmanaged(L"RpcWrapperTracker"); RpcLocalObjectTracker::RpcLocalObjectTracker(RpcLifecycleBase* lc, RpcObjectReference r) : lifecycle(lc), ref(r) { } RpcLocalObjectTracker::~RpcLocalObjectTracker() { if (lifecycle && lifecycle->IsTracked(ref.objectId)) { lifecycle->RemoveLocalObject(ref, false); } } void RpcLocalObjectTracker::Attach(RpcLifecycleBase* lc, RpcObjectReference r) { lifecycle = lc; ref = r; } void RpcLocalObjectTracker::Detach() { lifecycle = nullptr; } RpcWrapperTracker::RpcWrapperTracker(RpcLifecycleBase* lc, RpcObjectReference r) : lifecycle(lc), ref(r) { } RpcWrapperTracker::~RpcWrapperTracker() { if (lifecycle) { lifecycle->UntrackWrapper(ref); } } void RpcWrapperTracker::Detach() { lifecycle = nullptr; } /*********************************************************************** * RpcLifecycleBase (Constructor and Setup) ***********************************************************************/ RpcLifecycleBase::RpcLifecycleBase(vint _clientId) : clientId(_clientId) { } RpcLifecycleBase::~RpcLifecycleBase() { } void RpcLifecycleBase::SetIdMap(const Dictionary& _idMap) { CopyFrom(idMap, _idMap); } void RpcLifecycleBase::SetSerializer(Ptr _serializer) { serializer = _serializer; } IRpcSerializer* RpcLifecycleBase::GetSerializer() { return serializer.Obj(); } void RpcLifecycleBase::RegisterWrapperFactory(UniversalWrapperFactory factory) { universalWrapperFactory = factory; } void RpcLifecycleBase::DisconnectWrappersForFinalize() { #define ERROR_MESSAGE_PREFIX L"vl::rpc_controller::RpcLifecycleBase::DisconnectWrappersForFinalize()#" for (auto [ref, properties] : wrapperProperties) { if (properties.root) { auto trackerObj = properties.root->GetInternalProperty(InternalProperty_WrapperTracker); CHECK_ERROR(trackerObj, ERROR_MESSAGE_PREFIX L"Wrapper tracker missing."); auto tracker = trackerObj.Cast(); CHECK_ERROR(tracker, ERROR_MESSAGE_PREFIX L"Invalid wrapper tracker type."); tracker->Detach(); properties.root->SetInternalProperty(InternalProperty_WrapperTracker, nullptr); } if (properties.proxy) { properties.proxy->DisconnectFromLifecycle(); } } wrapperProperties.Clear(); #undef ERROR_MESSAGE_PREFIX } vint RpcLifecycleBase::DecideTypeId(IDescriptable* obj)const { if (dynamic_cast(obj)) return RpcTypeId_IValueObservableList; if (dynamic_cast(obj)) return RpcTypeId_IValueDictionary; if (dynamic_cast(obj)) return RpcTypeId_IValueArray; if (dynamic_cast(obj)) return RpcTypeId_IValueList; if (dynamic_cast(obj)) return RpcTypeId_IValueReadonlyList; if (dynamic_cast(obj)) return RpcTypeId_IValueEnumerator; if (dynamic_cast(obj)) return RpcTypeId_IValueEnumerable; return RpcTypeId_NotFound; } void RpcLifecycleBase::TrackLocalObject(RpcObjectReference ref, IDescriptable* obj) { #define ERROR_MESSAGE_PREFIX L"vl::rpc_controller::RpcLifecycleBase::TrackLocalObject(RpcObjectReference, reflection::IDescriptable*)#" auto index = localObjectProperties.Keys().IndexOf(ref.objectId); CHECK_ERROR(index != -1, ERROR_MESSAGE_PREFIX L"Object not registered."); auto props = localObjectProperties.Values().Get(index); CHECK_ERROR(props->rawPtr == nullptr, ERROR_MESSAGE_PREFIX L"Object already tracked."); props->rawPtr = obj; if (auto observable = dynamic_cast(obj)) { auto handler = observable->ItemChanged.Add([this, ref](vint index, vint oldCount, vint newCount) { if (this->GetController()->GetItemChangedSuppressedFlag(ref)) { return; } auto eventResult = this->GetDispatcher()->BroadcastFromClient_ListEventOps(this->GetClientId())->OnItemChanged(ref, index, oldCount, newCount); auto exceptions = serializer ? serializer->Deserialize(eventResult) : eventResult; ReadEventException(UnboxRpcEventExceptionMap(exceptions)); }); props->eventHandler = handler; } AttachLocalObjectEvents(ref, obj); if (auto descriptable = dynamic_cast(obj)) { Ptr tracker; if (auto trackerObj = descriptable->GetInternalProperty(InternalProperty_LocalObjectTracker)) { tracker = trackerObj.Cast(); CHECK_ERROR(tracker, ERROR_MESSAGE_PREFIX L"Invalid local object tracker type."); if (tracker->GetClientId() != ref.clientId) { throw Exception(ERROR_MESSAGE_PREFIX L"Object already tracked by a different client."); } CHECK_ERROR(!tracker->IsTracked(), ERROR_MESSAGE_PREFIX L"Object already tracked."); } else { tracker = Ptr(new RpcLocalObjectTracker(this, ref)); descriptable->SetInternalProperty(InternalProperty_LocalObjectTracker, tracker); } tracker->Attach(this, ref); } #undef ERROR_MESSAGE_PREFIX } void RpcLifecycleBase::UntrackLocalObject(RpcObjectReference ref, bool clearInternalProperty) { #define ERROR_MESSAGE_PREFIX L"vl::rpc_controller::RpcLifecycleBase::UntrackLocalObject(RpcObjectReference, bool)#" auto index = localObjectProperties.Keys().IndexOf(ref.objectId); CHECK_ERROR(index != -1, ERROR_MESSAGE_PREFIX L"Object not registered."); auto props = localObjectProperties.Values().Get(index); if (props->eventHandler) { if (auto observable = dynamic_cast(props->rawPtr)) { observable->ItemChanged.Remove(props->eventHandler); } props->eventHandler = nullptr; } auto rawPtr = props->rawPtr; props->rawPtr = nullptr; if (clearInternalProperty && rawPtr) { if (auto descriptable = dynamic_cast(rawPtr)) { if (auto trackerObj = descriptable->GetInternalProperty(InternalProperty_LocalObjectTracker)) { auto tracker = trackerObj.Cast(); CHECK_ERROR(tracker, ERROR_MESSAGE_PREFIX L"Invalid local object tracker type."); tracker->Detach(); descriptable->SetInternalProperty(InternalProperty_LocalObjectTracker, nullptr); } } } props->ownedPtr = nullptr; #undef ERROR_MESSAGE_PREFIX } void RpcLifecycleBase::RemoveLocalObject(RpcObjectReference ref, bool clearInternalProperty) { if (localObjectProperties.Keys().Contains(ref.objectId)) { UntrackLocalObject(ref, clearInternalProperty); localObjectProperties.Remove(ref.objectId); } } bool RpcLifecycleBase::IsTracked(vint objectId)const { auto index = localObjectProperties.Keys().IndexOf(objectId); return index != -1 && localObjectProperties.Values().Get(index)->rawPtr != nullptr; } void RpcLifecycleBase::TrackWrapper(DescriptableObject* root, IRpcWrapperBase* proxy, RpcObjectReference ref) { #define ERROR_MESSAGE_PREFIX L"vl::rpc_controller::RpcLifecycleBase::TrackWrapper(reflection::DescriptableObject*, IRpcWrapperBase*, RpcObjectReference)#" CHECK_ERROR(root != nullptr, ERROR_MESSAGE_PREFIX L"Wrapper does not implement DescriptableObject."); CHECK_ERROR(proxy != nullptr, ERROR_MESSAGE_PREFIX L"Wrapper is null."); #ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA root = root->SafeGetAggregationRoot(); #endif CHECK_ERROR(root->GetInternalProperty(InternalProperty_WrapperTracker) == nullptr, ERROR_MESSAGE_PREFIX L"Wrapper already tracked."); auto tracker = Ptr(new RpcWrapperTracker(this, ref)); root->SetInternalProperty(InternalProperty_WrapperTracker, tracker); RpcWrapperProperties properties; properties.root = root; properties.proxy = proxy; CHECK_ERROR(!wrapperProperties.Keys().Contains(ref), ERROR_MESSAGE_PREFIX L"Reference already tracked."); wrapperProperties.Set(ref, properties); #undef ERROR_MESSAGE_PREFIX } void RpcLifecycleBase::UntrackWrapper(RpcObjectReference ref) { wrapperProperties.Remove(ref); } bool RpcLifecycleBase::TryGetTrackedWrapperRef(DescriptableObject* obj, RpcObjectReference& ref)const { #define ERROR_MESSAGE_PREFIX L"vl::rpc_controller::RpcLifecycleBase::TryGetTrackedWrapperRef(reflection::DescriptableObject*, RpcObjectReference&)const#" auto wrapperRoot = obj; #ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA if (wrapperRoot) { wrapperRoot = wrapperRoot->SafeGetAggregationRoot(); } #endif if (wrapperRoot) { if (auto trackerObj = wrapperRoot->GetInternalProperty(InternalProperty_WrapperTracker)) { auto tracker = trackerObj.Cast(); CHECK_ERROR(tracker, ERROR_MESSAGE_PREFIX L"Invalid internal property type."); CHECK_ERROR(tracker->GetLifecycle() == this, ERROR_MESSAGE_PREFIX L"Wrapper registered to a different lifecycle."); ref = tracker->GetRef(); return true; } } return false; #undef ERROR_MESSAGE_PREFIX } IRpcWrapperBase* RpcLifecycleBase::GetTrackedWrapper(RpcObjectReference ref)const { if (auto index = wrapperProperties.Keys().IndexOf(ref); index != -1) { return wrapperProperties.Values()[index].proxy; } return nullptr; } Ptr RpcLifecycleBase::CreateCallerProxy(RpcObjectReference ref, IRpcSerializer* serializer) { #define ERROR_MESSAGE_PREFIX L"vl::rpc_controller::RpcLifecycleBase::CreateCallerProxy(RpcObjectReference)#" IRpcLifecycle* lc = this; Ptr wrapper; switch (ref.typeId) { case RpcTypeId_IValueEnumerable: wrapper = Ptr(new RpcByrefEnumerable(lc, ref, serializer)); break; case RpcTypeId_IValueEnumerator: wrapper = Ptr(new RpcByrefEnumerator(lc, ref, serializer)); break; case RpcTypeId_IValueArray: wrapper = Ptr(new RpcByrefArray(lc, ref, serializer)); break; case RpcTypeId_IValueReadonlyList: wrapper = Ptr(new RpcByrefReadonlyList(lc, ref, serializer)); break; case RpcTypeId_IValueList: wrapper = Ptr(new RpcByrefList(lc, ref, serializer)); break; case RpcTypeId_IValueObservableList: wrapper = Ptr(new RpcByrefObservableList(lc, ref, serializer)); break; case RpcTypeId_IValueDictionary: wrapper = Ptr(new RpcByrefDictionary(lc, ref, serializer)); break; default: CHECK_ERROR(universalWrapperFactory, ERROR_MESSAGE_PREFIX L"No wrapper factory registered."); wrapper = universalWrapperFactory(ref, this); CHECK_ERROR(wrapper, ERROR_MESSAGE_PREFIX L"Wrapper factory returned null."); break; } auto descriptable = dynamic_cast(wrapper.Obj()); CHECK_ERROR(descriptable, ERROR_MESSAGE_PREFIX L"Wrapper does not implement IDescriptable."); auto root = dynamic_cast(descriptable); TrackWrapper(root, wrapper.Obj(), ref); return Ptr(descriptable); #undef ERROR_MESSAGE_PREFIX } /*********************************************************************** * RpcLifecycleBase (IRpcLifecycle) ***********************************************************************/ void RpcLifecycleBase::Finalize() { DisconnectWrappersForFinalize(); while (localObjectProperties.Count() > 0) { auto props = localObjectProperties.Values().Get(localObjectProperties.Count() - 1); RemoveLocalObject(props->ref, true); } controller.Finalize(); } vint RpcLifecycleBase::GetClientId() { return clientId; } IRpcDispatcher* RpcLifecycleBase::GetDispatcher() { #define ERROR_MESSAGE_PREFIX L"vl::rpc_controller::RpcLifecycleBase::GetDispatcher()#" CHECK_ERROR(dispatcher, ERROR_MESSAGE_PREFIX L"No dispatcher registered."); return dispatcher; #undef ERROR_MESSAGE_PREFIX } RpcControllerDefault* RpcLifecycleBase::GetController() { return &controller; } void RpcLifecycleBase::LocalObjectHold(RpcObjectReference ref, vint remoteClientId) { #define ERROR_MESSAGE_PREFIX L"vl::rpc_controller::RpcLifecycleBase::LocalObjectHold(RpcObjectReference, vint)#" CHECK_ERROR(ref.clientId == clientId, ERROR_MESSAGE_PREFIX L"Ref is not local."); auto index = localObjectProperties.Keys().IndexOf(ref.objectId); CHECK_ERROR(index != -1, ERROR_MESSAGE_PREFIX L"Object not registered."); auto props = localObjectProperties.Values().Get(index); if (!props->interestedClients.Contains(remoteClientId)) { props->interestedClients.Add(remoteClientId); } #undef ERROR_MESSAGE_PREFIX } void RpcLifecycleBase::LocalObjectUnhold(RpcObjectReference ref, vint remoteClientId) { #define ERROR_MESSAGE_PREFIX L"vl::rpc_controller::RpcLifecycleBase::LocalObjectUnhold(RpcObjectReference, vint)#" CHECK_ERROR(ref.clientId == clientId, ERROR_MESSAGE_PREFIX L"Ref is not local."); auto index = localObjectProperties.Keys().IndexOf(ref.objectId); CHECK_ERROR(index != -1, ERROR_MESSAGE_PREFIX L"Object not registered."); auto props = localObjectProperties.Values().Get(index); CHECK_ERROR(props->interestedClients.Contains(remoteClientId), ERROR_MESSAGE_PREFIX L"Client does not hold this object."); props->interestedClients.Remove(remoteClientId); if (props->interestedClients.Count() == 0) { RemoveLocalObject(ref, true); } #undef ERROR_MESSAGE_PREFIX } void RpcLifecycleBase::RegisterService(const WString& fullName, Ptr service) { auto index = idMap.Keys().IndexOf(fullName); if (index == -1) { CHECK_FAIL(L"Unknown RPC type id."); } controller.GetObjectOps()->RegisterService(idMap.Values()[index], service); } Ptr RpcLifecycleBase::RequestService(const WString& fullName) { if (idMap.Keys().Contains(fullName)) { auto typeId = idMap.Get(fullName); auto ref = GetDispatcher()->RequestService(typeId); return RefToPtr(ref); } return nullptr; } Ptr RpcLifecycleBase::RefToPtr(RpcObjectReference ref) { return RefToPtr(ref, serializer.Obj()); } Ptr RpcLifecycleBase::RefToPtr(RpcObjectReference ref, IRpcSerializer* serializer) { #define ERROR_MESSAGE_PREFIX L"vl::rpc_controller::RpcLifecycleBase::RefToPtr(RpcObjectReference)#" if (ref.clientId == clientId) { auto index = localObjectProperties.Keys().IndexOf(ref.objectId); CHECK_ERROR(index != -1, ERROR_MESSAGE_PREFIX L"Object not registered."); auto props = localObjectProperties.Values().Get(index); CHECK_ERROR(props->rawPtr != nullptr, ERROR_MESSAGE_PREFIX L"Object not tracked."); return Ptr(props->rawPtr); } else { if (auto index = wrapperProperties.Keys().IndexOf(ref); index != -1) { auto proxy = wrapperProperties.Values()[index].proxy; auto descriptable = dynamic_cast(proxy); CHECK_ERROR(descriptable, ERROR_MESSAGE_PREFIX L"Wrapper does not implement IDescriptable."); return Ptr(descriptable); } return CreateCallerProxy(ref, serializer); } #undef ERROR_MESSAGE_PREFIX } RpcObjectReference RpcLifecycleBase::PtrToRef(Ptr obj) { #define ERROR_MESSAGE_PREFIX L"vl::rpc_controller::RpcLifecycleBase::PtrToRef(Ptr)#" CHECK_ERROR(obj, ERROR_MESSAGE_PREFIX L"A value is required."); if (auto descObj = dynamic_cast(obj.Obj())) { RpcObjectReference wrapperRef; if (TryGetTrackedWrapperRef(descObj, wrapperRef)) { return wrapperRef; } if (IsRpcWrapperObject(descObj)) { CHECK_FAIL(ERROR_MESSAGE_PREFIX L"Wrapper tracker lookup unexpectedly failed."); } } if (auto descObj = dynamic_cast(obj.Obj())) { if (auto trackerObj = descObj->GetInternalProperty(InternalProperty_LocalObjectTracker)) { auto tracker = trackerObj.Cast(); CHECK_ERROR(tracker, ERROR_MESSAGE_PREFIX L"Invalid internal property type."); if (tracker->GetClientId() != clientId) { throw Exception(ERROR_MESSAGE_PREFIX L"Object registered to a different lifecycle."); } if (tracker->IsTracked()) { CHECK_ERROR(tracker->GetLifecycle() == this, ERROR_MESSAGE_PREFIX L"Object tracker registered to an invalid lifecycle instance."); return tracker->GetRef(); } } } auto typeId = DecideTypeId(obj.Obj()); CHECK_ERROR(typeId != RpcTypeId_NotFound, ERROR_MESSAGE_PREFIX L"DecideTypeId returned RpcTypeId_NotFound (unknown type)."); auto ref = RpcObjectReference{ clientId, ++nextObjectId, typeId }; CHECK_ERROR(!localObjectProperties.Keys().Contains(ref.objectId), ERROR_MESSAGE_PREFIX L"Object ID already registered."); auto props = Ptr(new RpcLocalObjectProperties); props->ref = ref; props->ownedPtr = obj; localObjectProperties.Set(ref.objectId, props); TrackLocalObject(ref, obj.Obj()); return ref; #undef ERROR_MESSAGE_PREFIX } } } /*********************************************************************** .\RPC\WFLIBRARYRPCWRAPPERS.CPP ***********************************************************************/ namespace vl { using namespace collections; namespace rpc_controller { using namespace reflection; using namespace reflection::description; namespace { bool IsRpcObjectReferenceValue(const Value& value) { return value.GetValueType() == Value::BoxedValue && value.GetBoxedValue().Cast>(); } RpcObjectReference GetRpcObjectReference(const Value& value) { auto boxed = value.GetBoxedValue().Cast>(); CHECK_ERROR(boxed, L"RpcObjectReference is expected."); return boxed->value; } bool IsNullRpcObjectReference(RpcObjectReference ref) { return ref.clientId == RpcClientId_Invalid && ref.objectId == RpcObjectId_Invalid && ref.typeId == RpcTypeId_NotFound; } IRpcWrapperBase* CastRpcWrapperBase(IDescriptable* obj) { if (!obj) return nullptr; if (auto wrapper = dynamic_cast(obj)) return wrapper; return obj->SafeAggregationCast(); } template TInterface* CastRpcInterface(IDescriptable* obj) { if (!obj) return nullptr; if (auto proxy = dynamic_cast(obj)) return proxy; return obj->SafeAggregationCast(); } template bool ContainsKey(const Dictionary& xs, const K& key) { return xs.Keys().Contains(key); } template Ptr CreateTrackedProxy(IRpcLifecycle* lc, RpcObjectReference ref, IRpcSerializer* serializer) { auto obj = [&]() { if (auto lifecycle = dynamic_cast(lc)) { return lifecycle->RefToPtr(ref, serializer); } return lc->RefToPtr(ref); }(); CHECK_ERROR(obj, L"RPC proxy creation returned null."); if (auto wrapper = Ptr(CastRpcWrapperBase(obj.Obj()))) { auto proxy = Ptr(CastRpcInterface(obj.Obj())); CHECK_ERROR(proxy, L"RPC proxy creation returned an unexpected type."); return proxy; } return Ptr(new TWrapper(lc, ref, serializer)); } void SetRemoteObjectHold(IRpcLifecycle* lc, RpcObjectReference ref, bool hold) { lc->GetDispatcher()->SendToClient_ObjectOps(ref.clientId)->ObjectHold(ref, lc->GetClientId(), hold); } IRpcListOps* GetRemoteListOps(IRpcLifecycle* lc, RpcObjectReference ref) { return lc->GetDispatcher()->SendToClient_ListOps(ref.clientId); } Value SerializeValue(IRpcSerializer* serializer, const Value& value) { return serializer ? serializer->Serialize(value) : value; } Value DeserializeValue(IRpcSerializer* serializer, const Value& value) { return serializer ? serializer->Deserialize(value) : value; } extern Value RpcBoxValueByref(const Value& trivial, IRpcLifecycle* lc); extern Value RpcUnboxValueByref(const Value& serializable, IRpcLifecycle* lc); extern Value RpcCopyValueByvalInternal(const Value& trivial, Dictionary& visited); extern Value RpcBoxValueByvalInternal(const Value& trivial, IRpcLifecycle* lc, Dictionary& visited); extern Value RpcUnboxValueByvalInternal(const Value& serializable, IRpcLifecycle* lc, Dictionary& visited); } /*********************************************************************** * RpcByrefEnumerator ***********************************************************************/ RpcByrefEnumerator::RpcByrefEnumerator(IRpcLifecycle* lc, RpcObjectReference enumeratorRef, IRpcSerializer* _serializer) : lifecycle(lc) , serializer(_serializer) , ref(enumeratorRef) { if (!lifecycle) CHECK_FAIL(L"Invalid IRpcLifecycle."); SetRemoteObjectHold(lifecycle, ref, true); } RpcByrefEnumerator::~RpcByrefEnumerator() { if (lifecycle) SetRemoteObjectHold(lifecycle, ref, false); } void RpcByrefEnumerator::DisconnectFromLifecycle() { lifecycle = nullptr; } Value RpcByrefEnumerator::GetCurrent() { return RpcUnboxValueByref(DeserializeValue(serializer, GetRemoteListOps(lifecycle, ref)->EnumGetCurrent(ref)), lifecycle); } vint RpcByrefEnumerator::GetIndex() { return index; } bool RpcByrefEnumerator::Next() { if (GetRemoteListOps(lifecycle, ref)->EnumNext(ref)) { index++; return true; } return false; } RpcByrefEnumerable::RpcByrefEnumerable(IRpcLifecycle* lc, RpcObjectReference enumerableRef, IRpcSerializer* _serializer) : lifecycle(lc) , serializer(_serializer) , ref(enumerableRef) { if (!lifecycle) CHECK_FAIL(L"Invalid IRpcLifecycle."); SetRemoteObjectHold(lifecycle, ref, true); } RpcByrefEnumerable::~RpcByrefEnumerable() { if (lifecycle) SetRemoteObjectHold(lifecycle, ref, false); } void RpcByrefEnumerable::DisconnectFromLifecycle() { lifecycle = nullptr; } Ptr RpcByrefEnumerable::CreateEnumerator() { return CreateTrackedProxy(lifecycle, GetRemoteListOps(lifecycle, ref)->EnumCreate(ref), serializer); } /*********************************************************************** * RpcByrefReadonlyList ***********************************************************************/ RpcByrefReadonlyList::RpcByrefReadonlyList(IRpcLifecycle* lc, RpcObjectReference listRef, IRpcSerializer* _serializer) : lifecycle(lc) , serializer(_serializer) , ref(listRef) { if (!lifecycle) CHECK_FAIL(L"Invalid IRpcLifecycle."); SetRemoteObjectHold(lifecycle, ref, true); } RpcByrefReadonlyList::~RpcByrefReadonlyList() { if (lifecycle) SetRemoteObjectHold(lifecycle, ref, false); } void RpcByrefReadonlyList::DisconnectFromLifecycle() { lifecycle = nullptr; } Ptr RpcByrefReadonlyList::CreateEnumerator() { return CreateTrackedProxy(lifecycle, GetRemoteListOps(lifecycle, ref)->EnumCreate(ref), serializer); } vint RpcByrefReadonlyList::GetCount() { return GetRemoteListOps(lifecycle, ref)->ListGetCount(ref); } Value RpcByrefReadonlyList::Get(vint index) { return RpcUnboxValueByref(DeserializeValue(serializer, GetRemoteListOps(lifecycle, ref)->ListGet(ref, index)), lifecycle); } bool RpcByrefReadonlyList::Contains(const Value& value) { return GetRemoteListOps(lifecycle, ref)->ListContains(ref, SerializeValue(serializer, RpcBoxValueByref(value, lifecycle))); } vint RpcByrefReadonlyList::IndexOf(const Value& value) { return GetRemoteListOps(lifecycle, ref)->ListIndexOf(ref, SerializeValue(serializer, RpcBoxValueByref(value, lifecycle))); } /*********************************************************************** * RpcByrefList ***********************************************************************/ RpcByrefList::RpcByrefList(IRpcLifecycle* lc, RpcObjectReference listRef, IRpcSerializer* _serializer) : RpcByrefReadonlyList(lc, listRef, _serializer) { } RpcByrefList::~RpcByrefList() { } Ptr RpcByrefList::CreateEnumerator() { return RpcByrefReadonlyList::CreateEnumerator(); } vint RpcByrefList::GetCount() { return RpcByrefReadonlyList::GetCount(); } Value RpcByrefList::Get(vint index) { return RpcByrefReadonlyList::Get(index); } bool RpcByrefList::Contains(const Value& value) { return RpcByrefReadonlyList::Contains(value); } vint RpcByrefList::IndexOf(const Value& value) { return RpcByrefReadonlyList::IndexOf(value); } void RpcByrefList::Set(vint index, const Value& value) { GetRemoteListOps(lifecycle, ref)->ListSet(ref, index, SerializeValue(serializer, RpcBoxValueByref(value, lifecycle))); } vint RpcByrefList::Add(const Value& value) { return GetRemoteListOps(lifecycle, ref)->ListAdd(ref, SerializeValue(serializer, RpcBoxValueByref(value, lifecycle))); } vint RpcByrefList::Insert(vint index, const Value& value) { return GetRemoteListOps(lifecycle, ref)->ListInsert(ref, index, SerializeValue(serializer, RpcBoxValueByref(value, lifecycle))); } bool RpcByrefList::Remove(const Value& value) { auto index = IndexOf(value); return index == -1 ? false : GetRemoteListOps(lifecycle, ref)->ListRemoveAt(ref, index); } bool RpcByrefList::RemoveAt(vint index) { return GetRemoteListOps(lifecycle, ref)->ListRemoveAt(ref, index); } void RpcByrefList::Clear() { GetRemoteListOps(lifecycle, ref)->ListClear(ref); } /*********************************************************************** * RpcByrefArray ***********************************************************************/ RpcByrefArray::RpcByrefArray(IRpcLifecycle* lc, RpcObjectReference arrayRef, IRpcSerializer* _serializer) : lifecycle(lc) , serializer(_serializer) , ref(arrayRef) { if (!lifecycle) CHECK_FAIL(L"Invalid IRpcLifecycle."); SetRemoteObjectHold(lifecycle, ref, true); } RpcByrefArray::~RpcByrefArray() { if (lifecycle) SetRemoteObjectHold(lifecycle, ref, false); } void RpcByrefArray::DisconnectFromLifecycle() { lifecycle = nullptr; } Ptr RpcByrefArray::CreateEnumerator() { return CreateTrackedProxy(lifecycle, GetRemoteListOps(lifecycle, ref)->EnumCreate(ref), serializer); } vint RpcByrefArray::GetCount() { return GetRemoteListOps(lifecycle, ref)->ListGetCount(ref); } Value RpcByrefArray::Get(vint index) { return RpcUnboxValueByref(DeserializeValue(serializer, GetRemoteListOps(lifecycle, ref)->ListGet(ref, index)), lifecycle); } bool RpcByrefArray::Contains(const Value& value) { return GetRemoteListOps(lifecycle, ref)->ListContains(ref, SerializeValue(serializer, RpcBoxValueByref(value, lifecycle))); } vint RpcByrefArray::IndexOf(const Value& value) { return GetRemoteListOps(lifecycle, ref)->ListIndexOf(ref, SerializeValue(serializer, RpcBoxValueByref(value, lifecycle))); } void RpcByrefArray::Set(vint index, const Value& value) { GetRemoteListOps(lifecycle, ref)->ListSet(ref, index, SerializeValue(serializer, RpcBoxValueByref(value, lifecycle))); } void RpcByrefArray::Resize(vint size) { auto count = GetCount(); if (size > count) CHECK_FAIL(L"RpcByrefArray::Resize cannot grow."); for (vint i = count - 1; i >= size; i--) { GetRemoteListOps(lifecycle, ref)->ListRemoveAt(ref, i); } } /*********************************************************************** * RpcByrefObservableList ***********************************************************************/ RpcByrefObservableList::RpcByrefObservableList(IRpcLifecycle* lc, RpcObjectReference listRef, IRpcSerializer* _serializer) : lifecycle(lc) , serializer(_serializer) , ref(listRef) { if (!lifecycle) CHECK_FAIL(L"Invalid IRpcLifecycle."); SetRemoteObjectHold(lifecycle, ref, true); } RpcByrefObservableList::~RpcByrefObservableList() { if (lifecycle) SetRemoteObjectHold(lifecycle, ref, false); } void RpcByrefObservableList::DisconnectFromLifecycle() { lifecycle = nullptr; } Ptr RpcByrefObservableList::CreateEnumerator() { return CreateTrackedProxy(lifecycle, GetRemoteListOps(lifecycle, ref)->EnumCreate(ref), serializer); } vint RpcByrefObservableList::GetCount() { return GetRemoteListOps(lifecycle, ref)->ListGetCount(ref); } Value RpcByrefObservableList::Get(vint index) { return RpcUnboxValueByref(DeserializeValue(serializer, GetRemoteListOps(lifecycle, ref)->ListGet(ref, index)), lifecycle); } bool RpcByrefObservableList::Contains(const Value& value) { return GetRemoteListOps(lifecycle, ref)->ListContains(ref, SerializeValue(serializer, RpcBoxValueByref(value, lifecycle))); } vint RpcByrefObservableList::IndexOf(const Value& value) { return GetRemoteListOps(lifecycle, ref)->ListIndexOf(ref, SerializeValue(serializer, RpcBoxValueByref(value, lifecycle))); } void RpcByrefObservableList::Set(vint index, const Value& value) { GetRemoteListOps(lifecycle, ref)->ListSet(ref, index, SerializeValue(serializer, RpcBoxValueByref(value, lifecycle))); } vint RpcByrefObservableList::Add(const Value& value) { return GetRemoteListOps(lifecycle, ref)->ListAdd(ref, SerializeValue(serializer, RpcBoxValueByref(value, lifecycle))); } vint RpcByrefObservableList::Insert(vint index, const Value& value) { return GetRemoteListOps(lifecycle, ref)->ListInsert(ref, index, SerializeValue(serializer, RpcBoxValueByref(value, lifecycle))); } bool RpcByrefObservableList::Remove(const Value& value) { auto index = IndexOf(value); return index == -1 ? false : GetRemoteListOps(lifecycle, ref)->ListRemoveAt(ref, index); } bool RpcByrefObservableList::RemoveAt(vint index) { return GetRemoteListOps(lifecycle, ref)->ListRemoveAt(ref, index); } void RpcByrefObservableList::Clear() { GetRemoteListOps(lifecycle, ref)->ListClear(ref); } /*********************************************************************** * RpcByrefDictionary ***********************************************************************/ RpcByrefDictionary::RpcByrefDictionary(IRpcLifecycle* lc, RpcObjectReference dictRef, IRpcSerializer* _serializer) : lifecycle(lc) , serializer(_serializer) , ref(dictRef) { if (!lifecycle) CHECK_FAIL(L"Invalid IRpcLifecycle."); SetRemoteObjectHold(lifecycle, ref, true); } RpcByrefDictionary::~RpcByrefDictionary() { if (lifecycle) SetRemoteObjectHold(lifecycle, ref, false); } void RpcByrefDictionary::DisconnectFromLifecycle() { lifecycle = nullptr; } Ptr RpcByrefDictionary::GetKeys() { return CreateTrackedProxy(lifecycle, GetRemoteListOps(lifecycle, ref)->DictGetKeys(ref), serializer); } Ptr RpcByrefDictionary::GetValues() { return CreateTrackedProxy(lifecycle, GetRemoteListOps(lifecycle, ref)->DictGetValues(ref), serializer); } vint RpcByrefDictionary::GetCount() { return GetRemoteListOps(lifecycle, ref)->DictGetCount(ref); } Value RpcByrefDictionary::Get(const Value& key) { auto serializedKey = SerializeValue(serializer, RpcBoxValueByref(key, lifecycle)); auto serializedValue = GetRemoteListOps(lifecycle, ref)->DictGet(ref, serializedKey); return RpcUnboxValueByref(DeserializeValue(serializer, serializedValue), lifecycle); } void RpcByrefDictionary::Set(const Value& key, const Value& value) { auto serializedKey = SerializeValue(serializer, RpcBoxValueByref(key, lifecycle)); auto serializedValue = SerializeValue(serializer, RpcBoxValueByref(value, lifecycle)); GetRemoteListOps(lifecycle, ref)->DictSet(ref, serializedKey, serializedValue); } bool RpcByrefDictionary::Remove(const Value& key) { return GetRemoteListOps(lifecycle, ref)->DictRemove(ref, SerializeValue(serializer, RpcBoxValueByref(key, lifecycle))); } void RpcByrefDictionary::Clear() { GetRemoteListOps(lifecycle, ref)->DictClear(ref); } /*********************************************************************** * RpcCalleeListOps ***********************************************************************/ RpcCalleeListOps::RpcCalleeListOps(IRpcLifecycle* lc, IRpcSerializer* _serializer) : lifecycle(lc) , serializer(_serializer) { if (!lifecycle) CHECK_FAIL(L"Invalid IRpcLifecycle."); } RpcObjectReference RpcCalleeListOps::EnumCreate(RpcObjectReference ref) { auto obj = lifecycle->RefToPtr(ref); Ptr enumerator; if (auto xs = Ptr(obj.Obj()->SafeAggregationCast())) { enumerator = xs->CreateEnumerator(); } else { CHECK_FAIL(L"RpcCalleeListOps::EnumCreate cannot find the target collection."); return {}; } return lifecycle->PtrToRef(enumerator); } bool RpcCalleeListOps::EnumNext(RpcObjectReference enumerator) { auto obj = lifecycle->RefToPtr(enumerator); auto e = Ptr(obj.Obj()->SafeAggregationCast()); CHECK_ERROR(e, L"RpcCalleeListOps::EnumNext cannot find the target enumerator."); return e->Next(); } Value RpcCalleeListOps::EnumGetCurrent(RpcObjectReference enumerator) { auto obj = lifecycle->RefToPtr(enumerator); auto e = Ptr(obj.Obj()->SafeAggregationCast()); CHECK_ERROR(e, L"RpcCalleeListOps::EnumGetCurrent cannot find the target enumerator."); return SerializeValue(serializer, RpcBoxValueByref(e->GetCurrent(), lifecycle)); } vint RpcCalleeListOps::ListGetCount(RpcObjectReference ref) { auto obj = lifecycle->RefToPtr(ref); if (auto roList = Ptr(obj.Obj()->SafeAggregationCast())) return roList->GetCount(); CHECK_FAIL(L"RpcCalleeListOps::ListGetCount cannot find the target list."); return 0; } Value RpcCalleeListOps::ListGet(RpcObjectReference ref, vint index) { auto obj = lifecycle->RefToPtr(ref); if (auto roList = Ptr(obj.Obj()->SafeAggregationCast())) return SerializeValue(serializer, RpcBoxValueByref(roList->Get(index), lifecycle)); CHECK_FAIL(L"RpcCalleeListOps::ListGet cannot find the target list."); return {}; } void RpcCalleeListOps::ListSet(RpcObjectReference ref, vint index, const Value& value) { auto trivial = RpcUnboxValueByref(DeserializeValue(serializer, value), lifecycle); auto obj = lifecycle->RefToPtr(ref); if (auto array = Ptr(obj.Obj()->SafeAggregationCast())) { array->Set(index, trivial); return; } if (auto list = Ptr(obj.Obj()->SafeAggregationCast())) { list->Set(index, trivial); return; } CHECK_FAIL(L"RpcCalleeListOps::ListSet cannot find the target list."); } vint RpcCalleeListOps::ListAdd(RpcObjectReference ref, const Value& value) { auto trivial = RpcUnboxValueByref(DeserializeValue(serializer, value), lifecycle); auto obj = lifecycle->RefToPtr(ref); if (auto list = Ptr(obj.Obj()->SafeAggregationCast())) return list->Add(trivial); CHECK_FAIL(L"RpcCalleeListOps::ListAdd cannot find a writable list."); return -1; } vint RpcCalleeListOps::ListInsert(RpcObjectReference ref, vint index, const Value& value) { auto trivial = RpcUnboxValueByref(DeserializeValue(serializer, value), lifecycle); auto obj = lifecycle->RefToPtr(ref); if (auto list = Ptr(obj.Obj()->SafeAggregationCast())) return list->Insert(index, trivial); CHECK_FAIL(L"RpcCalleeListOps::ListInsert cannot find a writable list."); return -1; } bool RpcCalleeListOps::ListRemoveAt(RpcObjectReference ref, vint index) { auto obj = lifecycle->RefToPtr(ref); if (auto array = Ptr(obj.Obj()->SafeAggregationCast())) { CHECK_ERROR(index == array->GetCount() - 1, L"RpcCalleeListOps::ListRemoveAt only supports tail removal for arrays."); array->Resize(index); return true; } if (auto list = Ptr(obj.Obj()->SafeAggregationCast())) return list->RemoveAt(index); CHECK_FAIL(L"RpcCalleeListOps::ListRemoveAt cannot find the target list."); return false; } void RpcCalleeListOps::ListClear(RpcObjectReference ref) { auto obj = lifecycle->RefToPtr(ref); if (auto array = Ptr(obj.Obj()->SafeAggregationCast())) { array->Resize(0); return; } if (auto list = Ptr(obj.Obj()->SafeAggregationCast())) { list->Clear(); return; } CHECK_FAIL(L"RpcCalleeListOps::ListClear cannot find the target list."); } bool RpcCalleeListOps::ListContains(RpcObjectReference ref, const Value& value) { auto trivial = RpcUnboxValueByref(DeserializeValue(serializer, value), lifecycle); auto obj = lifecycle->RefToPtr(ref); if (auto roList = Ptr(obj.Obj()->SafeAggregationCast())) return roList->Contains(trivial); CHECK_FAIL(L"RpcCalleeListOps::ListContains cannot find the target list."); return false; } vint RpcCalleeListOps::ListIndexOf(RpcObjectReference ref, const Value& value) { auto trivial = RpcUnboxValueByref(DeserializeValue(serializer, value), lifecycle); auto obj = lifecycle->RefToPtr(ref); if (auto roList = Ptr(obj.Obj()->SafeAggregationCast())) return roList->IndexOf(trivial); CHECK_FAIL(L"RpcCalleeListOps::ListIndexOf cannot find the target list."); return -1; } vint RpcCalleeListOps::DictGetCount(RpcObjectReference ref) { auto obj = lifecycle->RefToPtr(ref); auto dict = Ptr(obj.Obj()->SafeAggregationCast()); CHECK_ERROR(dict, L"RpcCalleeListOps::DictGetCount cannot find the target dictionary."); return dict->GetCount(); } Value RpcCalleeListOps::DictGet(RpcObjectReference ref, const Value& key) { auto obj = lifecycle->RefToPtr(ref); auto dict = Ptr(obj.Obj()->SafeAggregationCast()); CHECK_ERROR(dict, L"RpcCalleeListOps::DictGet cannot find the target dictionary."); auto trivialKey = RpcUnboxValueByref(DeserializeValue(serializer, key), lifecycle); return SerializeValue(serializer, RpcBoxValueByref(dict->Get(trivialKey), lifecycle)); } void RpcCalleeListOps::DictSet(RpcObjectReference ref, const Value& key, const Value& value) { auto obj = lifecycle->RefToPtr(ref); auto dict = Ptr(obj.Obj()->SafeAggregationCast()); CHECK_ERROR(dict, L"RpcCalleeListOps::DictSet cannot find the target dictionary."); auto trivialKey = RpcUnboxValueByref(DeserializeValue(serializer, key), lifecycle); auto trivialValue = RpcUnboxValueByref(DeserializeValue(serializer, value), lifecycle); dict->Set(trivialKey, trivialValue); } bool RpcCalleeListOps::DictRemove(RpcObjectReference ref, const Value& key) { auto obj = lifecycle->RefToPtr(ref); auto dict = Ptr(obj.Obj()->SafeAggregationCast()); CHECK_ERROR(dict, L"RpcCalleeListOps::DictRemove cannot find the target dictionary."); return dict->Remove(RpcUnboxValueByref(DeserializeValue(serializer, key), lifecycle)); } void RpcCalleeListOps::DictClear(RpcObjectReference ref) { auto obj = lifecycle->RefToPtr(ref); auto dict = Ptr(obj.Obj()->SafeAggregationCast()); CHECK_ERROR(dict, L"RpcCalleeListOps::DictClear cannot find the target dictionary."); dict->Clear(); } bool RpcCalleeListOps::DictContainsKey(RpcObjectReference ref, const Value& key) { auto obj = lifecycle->RefToPtr(ref); auto dict = Ptr(obj.Obj()->SafeAggregationCast()); CHECK_ERROR(dict, L"RpcCalleeListOps::DictContainsKey cannot find the target dictionary."); return dict->GetKeys()->Contains(RpcUnboxValueByref(DeserializeValue(serializer, key), lifecycle)); } RpcObjectReference RpcCalleeListOps::DictGetKeys(RpcObjectReference ref) { auto obj = lifecycle->RefToPtr(ref); auto dict = Ptr(obj.Obj()->SafeAggregationCast()); CHECK_ERROR(dict, L"RpcCalleeListOps::DictGetKeys cannot find the target dictionary."); return lifecycle->PtrToRef(dict->GetKeys()); } RpcObjectReference RpcCalleeListOps::DictGetValues(RpcObjectReference ref) { auto obj = lifecycle->RefToPtr(ref); auto dict = Ptr(obj.Obj()->SafeAggregationCast()); CHECK_ERROR(dict, L"RpcCalleeListOps::DictGetValues cannot find the target dictionary."); return lifecycle->PtrToRef(dict->GetValues()); } /*********************************************************************** * RpcCalleeListEventBridge ***********************************************************************/ RpcCalleeListEventBridge::RpcCalleeListEventBridge(IRpcLifecycle* lc, IRpcSerializer* _serializer) : lifecycle(lc) , serializer(_serializer) { if (!lifecycle) CHECK_FAIL(L"Invalid IRpcLifecycle."); } Value RpcCalleeListEventBridge::OnItemChanged(RpcObjectReference ref, vint index, vint oldCount, vint newCount) { auto controller = lifecycle->GetController(); auto obj = lifecycle->RefToPtr(ref); auto observable = Ptr(obj.Obj()->SafeAggregationCast()); CHECK_ERROR(observable, L"RpcCalleeListEventBridge::OnItemChanged cannot find the target observable list."); controller->SetItemChangedSuppressedFlag(ref, true); RpcEventExceptionMap exceptions; try { observable->ItemChanged(index, oldCount, newCount); } catch (const Exception& ex) { exceptions = CreateRpcEventExceptionMap(); exceptions->Set(BoxValue(lifecycle->GetClientId()), BoxRpcException(RpcException{ ex.Message() })); } catch (...) { controller->SetItemChangedSuppressedFlag(ref, false); throw; } controller->SetItemChangedSuppressedFlag(ref, false); return SerializeValue(serializer, BoxRpcEventExceptionMap(exceptions)); } /*********************************************************************** * Helpers ***********************************************************************/ RpcObjectReference RpcBoxByref(Ptr trivial, IRpcLifecycle* lc) { if (!lc) CHECK_FAIL(L"IRpcLifecycle cannot be null."); if (!trivial) return {}; return lc->PtrToRef(trivial); } Ptr RpcUnboxByref(RpcObjectReference serializable, IRpcLifecycle* lc) { if (!lc) CHECK_FAIL(L"IRpcLifecycle cannot be null."); if (IsNullRpcObjectReference(serializable)) return nullptr; return lc->RefToPtr(serializable); } namespace { Value RpcBoxValueByref(const Value& trivial, IRpcLifecycle* lc) { if (!lc) CHECK_FAIL(L"IRpcLifecycle cannot be null."); if (trivial.IsNull()) return trivial; if (trivial.GetValueType() == Value::SharedPtr) { if (auto raw = trivial.GetRawPtr()) { if (auto obj = dynamic_cast(raw)) { return BoxValue(RpcBoxByref(Ptr(obj), lc)); } } } return trivial; } Value RpcUnboxValueByref(const Value& serializable, IRpcLifecycle* lc) { if (!lc) CHECK_FAIL(L"IRpcLifecycle cannot be null."); if (serializable.IsNull()) return serializable; if (IsRpcObjectReferenceValue(serializable)) { auto ref = GetRpcObjectReference(serializable); auto obj = RpcUnboxByref(ref, lc); return obj ? BoxValue(obj) : Value{}; } return serializable; } } namespace { template Ptr TryGetValueInterface(const Value& value) { if (auto raw = value.GetRawPtr()) { return Ptr(dynamic_cast(raw)); } return nullptr; } Value RpcCopyValueByvalInternal(const Value& trivial, Dictionary& visited) { if (trivial.IsNull()) return trivial; if (trivial.GetValueType() == Value::SharedPtr) { if (auto roDict = TryGetValueInterface(trivial)) { auto key = static_cast(trivial.GetRawPtr()); if (ContainsKey(visited, key)) CHECK_FAIL(L"Byval copying does not support cycles."); visited.Add(key, true); auto dict = IValueDictionary::Create(); auto keys = roDict->GetKeys(); for (vint i = 0; i < keys->GetCount(); i++) { auto dictKey = keys->Get(i); dict->Set( RpcCopyValueByvalInternal(dictKey, visited), RpcCopyValueByvalInternal(roDict->Get(dictKey), visited) ); } visited.Remove(key); return BoxValue(dict); } if (auto obsList = TryGetValueInterface(trivial)) { auto key = static_cast(trivial.GetRawPtr()); if (ContainsKey(visited, key)) CHECK_FAIL(L"Byval copying does not support cycles."); visited.Add(key, true); auto list = IValueObservableList::Create(); for (vint i = 0; i < obsList->GetCount(); i++) { list->Add(RpcCopyValueByvalInternal(obsList->Get(i), visited)); } visited.Remove(key); return BoxValue(list); } if (auto array = TryGetValueInterface(trivial)) { auto key = static_cast(trivial.GetRawPtr()); if (ContainsKey(visited, key)) CHECK_FAIL(L"Byval copying does not support cycles."); visited.Add(key, true); auto list = IValueArray::Create(); list->Resize(array->GetCount()); for (vint i = 0; i < array->GetCount(); i++) { list->Set(i, RpcCopyValueByvalInternal(array->Get(i), visited)); } visited.Remove(key); return BoxValue(list); } if (auto roList = TryGetValueInterface(trivial)) { auto key = static_cast(trivial.GetRawPtr()); if (ContainsKey(visited, key)) CHECK_FAIL(L"Byval copying does not support cycles."); visited.Add(key, true); auto list = IValueList::Create(); for (vint i = 0; i < roList->GetCount(); i++) { list->Add(RpcCopyValueByvalInternal(roList->Get(i), visited)); } visited.Remove(key); return BoxValue(list); } } return trivial; } Value RpcBoxValueByvalInternal(const Value& trivial, IRpcLifecycle* lc, Dictionary& visited) { if (trivial.IsNull()) return trivial; if (trivial.GetValueType() == Value::SharedPtr) { if (auto roDict = TryGetValueInterface(trivial)) { auto key = static_cast(trivial.GetRawPtr()); if (ContainsKey(visited, key)) CHECK_FAIL(L"Byval boxing does not support cycles."); visited.Add(key, true); auto dict = IValueDictionary::Create(); auto keys = roDict->GetKeys(); for (vint i = 0; i < keys->GetCount(); i++) { auto dictKey = keys->Get(i); dict->Set( RpcBoxValueByvalInternal(dictKey, lc, visited), RpcBoxValueByvalInternal(roDict->Get(dictKey), lc, visited) ); } visited.Remove(key); return BoxValue(dict); } if (auto obsList = TryGetValueInterface(trivial)) { auto key = static_cast(trivial.GetRawPtr()); if (ContainsKey(visited, key)) CHECK_FAIL(L"Byval boxing does not support cycles."); visited.Add(key, true); auto list = IValueObservableList::Create(); for (vint i = 0; i < obsList->GetCount(); i++) { list->Add(RpcBoxValueByvalInternal(obsList->Get(i), lc, visited)); } visited.Remove(key); return BoxValue(list); } if (auto array = TryGetValueInterface(trivial)) { auto key = static_cast(trivial.GetRawPtr()); if (ContainsKey(visited, key)) CHECK_FAIL(L"Byval boxing does not support cycles."); visited.Add(key, true); auto list = IValueArray::Create(); list->Resize(array->GetCount()); for (vint i = 0; i < array->GetCount(); i++) { list->Set(i, RpcBoxValueByvalInternal(array->Get(i), lc, visited)); } visited.Remove(key); return BoxValue(list); } if (auto roList = TryGetValueInterface(trivial)) { auto key = static_cast(trivial.GetRawPtr()); if (ContainsKey(visited, key)) CHECK_FAIL(L"Byval boxing does not support cycles."); visited.Add(key, true); auto list = IValueList::Create(); for (vint i = 0; i < roList->GetCount(); i++) { list->Add(RpcBoxValueByvalInternal(roList->Get(i), lc, visited)); } visited.Remove(key); return BoxValue(list); } if (auto raw = trivial.GetRawPtr()) { if (auto obj = dynamic_cast(raw)) { auto ref = lc->PtrToRef(Ptr(obj)); return BoxValue(ref); } } } return trivial; } } Value RpcCopyByval(const Value& trivial, IRpcLifecycle* lc) { if (!lc) CHECK_FAIL(L"IRpcLifecycle cannot be null."); if (trivial.IsNull()) return {}; Dictionary visited; return RpcCopyValueByvalInternal(trivial, visited); } Value RpcBoxByval(Ptr trivial, IRpcLifecycle* lc) { if (!lc) CHECK_FAIL(L"IRpcLifecycle cannot be null."); if (!trivial) return {}; return RpcBoxByval(BoxValue(trivial), lc); } Value RpcBoxByval(const Value& trivial, IRpcLifecycle* lc) { if (!lc) CHECK_FAIL(L"IRpcLifecycle cannot be null."); if (trivial.IsNull()) return {}; Dictionary visited; return RpcBoxValueByvalInternal(trivial, lc, visited); } namespace { Value RpcUnboxValueByvalInternal(const Value& serializable, IRpcLifecycle* lc, Dictionary& visited) { if (serializable.IsNull()) return serializable; if (IsRpcObjectReferenceValue(serializable)) { auto ref = GetRpcObjectReference(serializable); auto obj = RpcUnboxByref(ref, lc); return obj ? BoxValue(obj) : Value{}; } if (serializable.GetValueType() == Value::SharedPtr) { if (auto roDict = TryGetValueInterface(serializable)) { auto key = static_cast(serializable.GetRawPtr()); if (ContainsKey(visited, key)) CHECK_FAIL(L"Byval unboxing does not support cycles."); visited.Add(key, true); auto dict = IValueDictionary::Create(); auto keys = roDict->GetKeys(); for (vint i = 0; i < keys->GetCount(); i++) { auto dictKey = keys->Get(i); dict->Set( RpcUnboxValueByvalInternal(dictKey, lc, visited), RpcUnboxValueByvalInternal(roDict->Get(dictKey), lc, visited) ); } visited.Remove(key); return BoxValue(dict); } if (auto obsList = TryGetValueInterface(serializable)) { auto key = static_cast(serializable.GetRawPtr()); if (ContainsKey(visited, key)) CHECK_FAIL(L"Byval unboxing does not support cycles."); visited.Add(key, true); auto list = IValueObservableList::Create(); for (vint i = 0; i < obsList->GetCount(); i++) { list->Add(RpcUnboxValueByvalInternal(obsList->Get(i), lc, visited)); } visited.Remove(key); return BoxValue(list); } if (auto array = TryGetValueInterface(serializable)) { auto key = static_cast(serializable.GetRawPtr()); if (ContainsKey(visited, key)) CHECK_FAIL(L"Byval unboxing does not support cycles."); visited.Add(key, true); auto list = IValueArray::Create(); list->Resize(array->GetCount()); for (vint i = 0; i < array->GetCount(); i++) { list->Set(i, RpcUnboxValueByvalInternal(array->Get(i), lc, visited)); } visited.Remove(key); return BoxValue(list); } if (auto roList = TryGetValueInterface(serializable)) { auto key = static_cast(serializable.GetRawPtr()); if (ContainsKey(visited, key)) CHECK_FAIL(L"Byval unboxing does not support cycles."); visited.Add(key, true); auto list = IValueList::Create(); for (vint i = 0; i < roList->GetCount(); i++) { list->Add(RpcUnboxValueByvalInternal(roList->Get(i), lc, visited)); } visited.Remove(key); return BoxValue(list); } } return serializable; } } Ptr RpcUnboxByval(const Value& serializable, IRpcLifecycle* lc) { if (!lc) CHECK_FAIL(L"IRpcLifecycle cannot be null."); if (serializable.IsNull()) return nullptr; Dictionary visited; auto trivial = RpcUnboxValueByvalInternal(serializable, lc, visited); if (auto raw = trivial.GetRawPtr()) { if (auto obj = dynamic_cast(raw)) { return Ptr(obj); } } CHECK_FAIL(L"Interface value or null is expected."); return nullptr; } void ReadMethodException(const Value& value) { if (value.GetValueType() == Value::BoxedValue) { if (auto boxed = value.GetBoxedValue().Cast>()) { throw Exception(boxed->value.message); } } } void ReadEventException(RpcEventExceptionMap exceptions) { if (!exceptions || exceptions->GetCount() == 0) return; WString message; auto keys = exceptions->GetKeys(); for (vint i = 0; i < keys->GetCount(); i++) { auto key = keys->Get(i); auto exception = UnboxValue(exceptions->Get(key)); message += itow(UnboxValue(key)) + L":" + exception.message + L";"; } throw Exception(message); } } }