mirror of
https://github.com/vczh-libraries/Release.git
synced 2026-08-17 09:21:41 +08:00
3727 lines
120 KiB
C++
3727 lines
120 KiB
C++
/***********************************************************************
|
|
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<IValueArray> _list)
|
|
:list(_list)
|
|
{
|
|
}
|
|
|
|
/***********************************************************************
|
|
CreateList
|
|
***********************************************************************/
|
|
|
|
CreateList::CreateList()
|
|
:list(IValueList::Create())
|
|
{
|
|
}
|
|
|
|
CreateList::CreateList(Ptr<IValueList> _list)
|
|
:list(_list)
|
|
{
|
|
}
|
|
|
|
/***********************************************************************
|
|
CreateObservableList
|
|
***********************************************************************/
|
|
|
|
CreateObservableList::CreateObservableList()
|
|
:list(IValueObservableList::Create())
|
|
{
|
|
}
|
|
|
|
CreateObservableList::CreateObservableList(Ptr<IValueObservableList> _list)
|
|
:list(_list)
|
|
{
|
|
}
|
|
|
|
/***********************************************************************
|
|
CreateDictionary
|
|
***********************************************************************/
|
|
|
|
CreateDictionary::CreateDictionary()
|
|
:dictionary(IValueDictionary::Create())
|
|
{
|
|
}
|
|
|
|
CreateDictionary::CreateDictionary(Ptr<IValueDictionary> _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<IValueException> CoroutineResult::GetFailure()
|
|
{
|
|
return failure;
|
|
}
|
|
|
|
void CoroutineResult::SetFailure(Ptr<IValueException> value)
|
|
{
|
|
failure = value;
|
|
}
|
|
|
|
/***********************************************************************
|
|
EnumerableCoroutine
|
|
***********************************************************************/
|
|
|
|
class CoroutineEnumerator : public Object, public virtual EnumerableCoroutine::IImpl, public Description<CoroutineEnumerator>
|
|
{
|
|
protected:
|
|
EnumerableCoroutine::Creator creator;
|
|
Ptr<ICoroutine> coroutine;
|
|
Value current;
|
|
vint index = -1;
|
|
Ptr<IValueEnumerator> 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<IValueEnumerable> 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<CoroutineEnumerable>
|
|
{
|
|
protected:
|
|
EnumerableCoroutine::Creator creator;
|
|
|
|
public:
|
|
CoroutineEnumerable(const EnumerableCoroutine::Creator& _creator)
|
|
:creator(_creator)
|
|
{
|
|
}
|
|
|
|
Ptr<IValueEnumerator> CreateEnumerator()override
|
|
{
|
|
return Ptr(new CoroutineEnumerator(creator));
|
|
}
|
|
};
|
|
|
|
void EnumerableCoroutine::YieldAndPause(IImpl* impl, const Value& value)
|
|
{
|
|
impl->OnYield(value);
|
|
}
|
|
|
|
void EnumerableCoroutine::JoinAndPause(IImpl* impl, Ptr<IValueEnumerable> value)
|
|
{
|
|
impl->OnJoin(value);
|
|
}
|
|
|
|
void EnumerableCoroutine::ReturnAndExit(IImpl* impl)
|
|
{
|
|
}
|
|
|
|
Ptr<IValueEnumerable> 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<DelayAsync>
|
|
{
|
|
protected:
|
|
SpinLock lock;
|
|
vint milliseconds;
|
|
AsyncStatus status = AsyncStatus::Ready;
|
|
|
|
public:
|
|
DelayAsync(vint _milliseconds)
|
|
:milliseconds(_milliseconds)
|
|
{
|
|
}
|
|
|
|
AsyncStatus GetStatus()override
|
|
{
|
|
return status;
|
|
}
|
|
|
|
bool Execute(const Func<void(Ptr<CoroutineResult>)>& _callback, Ptr<AsyncContext> context)override
|
|
{
|
|
SPIN_LOCK(lock)
|
|
{
|
|
if (status != AsyncStatus::Ready) return false;
|
|
status = AsyncStatus::Executing;
|
|
IAsyncScheduler::GetSchedulerForCurrentThread()->DelayExecute([async = Ptr<DelayAsync>(this), callback = _callback]()
|
|
{
|
|
if (callback)
|
|
{
|
|
callback(nullptr);
|
|
}
|
|
}, milliseconds);
|
|
}
|
|
return true;
|
|
}
|
|
};
|
|
|
|
Ptr<IAsync> IAsync::Delay(vint milliseconds)
|
|
{
|
|
return Ptr(new DelayAsync(milliseconds));
|
|
}
|
|
|
|
/***********************************************************************
|
|
FutureAndPromiseAsync
|
|
***********************************************************************/
|
|
|
|
class FutureAndPromiseAsync : public virtual IFuture, public virtual IPromise, public Description<FutureAndPromiseAsync>
|
|
{
|
|
public:
|
|
SpinLock lock;
|
|
AsyncStatus status = AsyncStatus::Ready;
|
|
Ptr<CoroutineResult> cr;
|
|
Func<void(Ptr<CoroutineResult>)> callback;
|
|
|
|
void ExecuteCallbackAndClear()
|
|
{
|
|
status = AsyncStatus::Stopped;
|
|
if (callback)
|
|
{
|
|
callback(cr);
|
|
}
|
|
cr = nullptr;
|
|
callback = {};
|
|
}
|
|
|
|
template<typename F>
|
|
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<void(Ptr<CoroutineResult>)>& _callback, Ptr<AsyncContext> context)override
|
|
{
|
|
SPIN_LOCK(lock)
|
|
{
|
|
if (status != AsyncStatus::Ready) return false;
|
|
callback = _callback;
|
|
if (cr)
|
|
{
|
|
ExecuteCallbackAndClear();
|
|
}
|
|
else
|
|
{
|
|
status = AsyncStatus::Executing;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
Ptr<IPromise> GetPromise()override
|
|
{
|
|
return Ptr(this);
|
|
}
|
|
|
|
bool SendResult(const Value& result)override
|
|
{
|
|
return Send([=, this]()
|
|
{
|
|
cr->SetResult(result);
|
|
});
|
|
}
|
|
|
|
bool SendFailure(Ptr<IValueException> failure)override
|
|
{
|
|
return Send([=, this]()
|
|
{
|
|
cr->SetFailure(failure);
|
|
});
|
|
}
|
|
};
|
|
|
|
Ptr<IFuture> IFuture::Create()
|
|
{
|
|
return Ptr(new FutureAndPromiseAsync);
|
|
}
|
|
|
|
/***********************************************************************
|
|
IAsyncScheduler
|
|
***********************************************************************/
|
|
|
|
class AsyncSchedulerMap
|
|
{
|
|
public:
|
|
Dictionary<vint, Ptr<IAsyncScheduler>> schedulers;
|
|
Ptr<IAsyncScheduler> 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<IAsyncScheduler> 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<IAsyncScheduler> 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> IAsyncScheduler::UnregisterDefaultScheduler()
|
|
{
|
|
Ptr<IAsyncScheduler> scheduler;
|
|
SPIN_LOCK(asyncSchedulerLock)
|
|
{
|
|
if (asyncSchedulerMap)
|
|
{
|
|
scheduler = asyncSchedulerMap->defaultScheduler;
|
|
asyncSchedulerMap->defaultScheduler = nullptr;
|
|
DISPOSE_ASYNC_SCHEDULER_MAP_IF_NECESSARY
|
|
}
|
|
}
|
|
return scheduler;
|
|
}
|
|
|
|
Ptr<IAsyncScheduler> IAsyncScheduler::UnregisterSchedulerForCurrentThread()
|
|
{
|
|
Ptr<IAsyncScheduler> 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> IAsyncScheduler::GetSchedulerForCurrentThread()
|
|
{
|
|
Ptr<IAsyncScheduler> 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<CoroutineAsync>
|
|
{
|
|
protected:
|
|
Ptr<ICoroutine> coroutine;
|
|
AsyncCoroutine::Creator creator;
|
|
Ptr<IAsyncScheduler> scheduler;
|
|
Func<void(Ptr<CoroutineResult>)> callback;
|
|
Ptr<AsyncContext> 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<void(Ptr<CoroutineResult>)>& _callback, Ptr<AsyncContext> _context)override
|
|
{
|
|
if (coroutine) return false;
|
|
scheduler = IAsyncScheduler::GetSchedulerForCurrentThread();
|
|
callback = _callback;
|
|
context = _context;
|
|
coroutine = creator(this);
|
|
OnContinue(nullptr);
|
|
return true;
|
|
}
|
|
|
|
Ptr<IAsyncScheduler> GetScheduler()override
|
|
{
|
|
return scheduler;
|
|
}
|
|
|
|
Ptr<AsyncContext> GetContext()override
|
|
{
|
|
if (!context)
|
|
{
|
|
context = Ptr(new AsyncContext);
|
|
}
|
|
return context;
|
|
}
|
|
|
|
void OnContinue(Ptr<CoroutineResult> output)override
|
|
{
|
|
scheduler->Execute([async = Ptr<CoroutineAsync>(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<IAsync> value)
|
|
{
|
|
value->Execute([async = Ptr<IImpl>(impl)](auto output)
|
|
{
|
|
async->OnContinue(output);
|
|
}, impl->GetContext());
|
|
}
|
|
|
|
void AsyncCoroutine::ReturnAndExit(IImpl* impl, const Value& value)
|
|
{
|
|
impl->OnReturn(value);
|
|
}
|
|
|
|
Ptr<AsyncContext> AsyncCoroutine::QueryContext(IImpl* impl)
|
|
{
|
|
return impl->GetContext();
|
|
}
|
|
|
|
Ptr<IAsync> AsyncCoroutine::Create(const Creator& creator)
|
|
{
|
|
return Ptr(new CoroutineAsync(creator));
|
|
}
|
|
void AsyncCoroutine::CreateAndRun(const Creator& creator)
|
|
{
|
|
Ptr(new CoroutineAsync(creator))->Execute(
|
|
[](Ptr<CoroutineResult> 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<CoroutineResult> 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<IValueReadonlyList> list;
|
|
|
|
class Enumerator : public Object, public IValueEnumerator
|
|
{
|
|
protected:
|
|
Ptr<IValueReadonlyList> list;
|
|
vint index;
|
|
|
|
public:
|
|
Enumerator(Ptr<IValueReadonlyList> _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<IValueReadonlyList> _list)
|
|
:list(_list)
|
|
{
|
|
}
|
|
|
|
Ptr<IValueEnumerator> 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<IValueEnumerable> Sys::ReverseEnumerable(Ptr<IValueEnumerable> value)
|
|
{
|
|
auto list = value.Cast<IValueReadonlyList>();
|
|
if (!list)
|
|
{
|
|
list = IValueList::Create(GetLazyList<Value>(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<Locale> Localization::Locales()
|
|
{
|
|
auto result = Ptr(new List<Locale>);
|
|
Locale::Enumerate(*result.Obj());
|
|
return result;
|
|
}
|
|
|
|
collections::LazyList<WString> Localization::GetShortDateFormats(Locale locale)
|
|
{
|
|
auto result = Ptr(new List<WString>);
|
|
locale.GetShortDateFormats(*result.Obj());
|
|
return result;
|
|
}
|
|
|
|
collections::LazyList<WString> Localization::GetLongDateFormats(Locale locale)
|
|
{
|
|
auto result = Ptr(new List<WString>);
|
|
locale.GetLongDateFormats(*result.Obj());
|
|
return result;
|
|
}
|
|
|
|
collections::LazyList<WString> Localization::GetYearMonthDateFormats(Locale locale)
|
|
{
|
|
auto result = Ptr(new List<WString>);
|
|
locale.GetYearMonthDateFormats(*result.Obj());
|
|
return result;
|
|
}
|
|
|
|
collections::LazyList<WString> Localization::GetLongTimeFormats(Locale locale)
|
|
{
|
|
auto result = Ptr(new List<WString>);
|
|
locale.GetLongTimeFormats(*result.Obj());
|
|
return result;
|
|
}
|
|
|
|
collections::LazyList<WString> Localization::GetShortTimeFormats(Locale locale)
|
|
{
|
|
auto result = Ptr(new List<WString>);
|
|
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 <limits.h>
|
|
#include <float.h>
|
|
|
|
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<vl::rpc_controller::RpcByvalReturnValue>(), 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::reflection::IDescriptable>, vl::rpc_controller::IRpcLifecycle*), vl::rpc_controller::RpcBoxByref)
|
|
CLASS_MEMBER_STATIC_EXTERNALMETHOD(RpcUnboxByref, { L"serializable" _ L"lc" }, vl::Ptr<vl::reflection::IDescriptable>(*)(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<vl::reflection::IDescriptable>(*)(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<vl::glr::json::JsonNode>(*)(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<CoroutineResult>(), 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<AsyncContext>(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<StateMachine>(), 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<Versioning>(), 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<RpcObjectReference>(ref)), nullptr);
|
|
}
|
|
|
|
Value BoxRpcException(RpcException exception)
|
|
{
|
|
return Value::From(Ptr(new IValueType::TypedBox<RpcException>(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<RpcEventExceptionMap>(value);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
.\RPC\WFLIBRARYRPCCONTROLLER.CPP
|
|
***********************************************************************/
|
|
|
|
namespace vl
|
|
{
|
|
namespace rpc_controller
|
|
{
|
|
using namespace collections;
|
|
|
|
/***********************************************************************
|
|
* RpcControllerDefault
|
|
***********************************************************************/
|
|
|
|
RpcControllerDefault::RpcControllerDefault()
|
|
{
|
|
}
|
|
|
|
RpcControllerDefault::~RpcControllerDefault()
|
|
{
|
|
}
|
|
|
|
void RpcControllerDefault::Register(Ptr<IRpcObjectOps> _objectCallback, Ptr<IRpcObjectEventOps> _eventCallback, Ptr<IRpcListOps> _listCallback, Ptr<IRpcListEventOps> _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<typename TKey>
|
|
void RpcControllerDefault::SetSuppressedFlag(Dictionary<TKey, vint>& flags, const TKey& key, bool suppressed)
|
|
{
|
|
#define ERROR_MESSAGE_PREFIX L"vl::rpc_controller::RpcControllerDefault::SetSuppressedFlag(collections::Dictionary<TKey, vint>&, 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<typename TKey>
|
|
bool RpcControllerDefault::GetSuppressedFlag(const Dictionary<TKey, vint>& 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<JsonLiteral> CreateJsonLiteral(JsonLiteralValue value)
|
|
{
|
|
auto node = Ptr(new JsonLiteral);
|
|
node->value = value;
|
|
return node;
|
|
}
|
|
|
|
Ptr<JsonString> CreateJsonString(const WString& value)
|
|
{
|
|
auto node = Ptr(new JsonString);
|
|
node->content.value = value;
|
|
return node;
|
|
}
|
|
|
|
Ptr<JsonNumber> CreateJsonNumber(const WString& value)
|
|
{
|
|
auto node = Ptr(new JsonNumber);
|
|
node->content.value = value;
|
|
return node;
|
|
}
|
|
|
|
Ptr<JsonArray> CreateJsonArray()
|
|
{
|
|
return Ptr(new JsonArray);
|
|
}
|
|
|
|
Ptr<JsonObject> CreateJsonObject()
|
|
{
|
|
return Ptr(new JsonObject);
|
|
}
|
|
|
|
void AddJsonObjectField(Ptr<JsonObject> object, const WString& name, Ptr<JsonNode> value)
|
|
{
|
|
auto field = Ptr(new JsonObjectField);
|
|
field->name.value = name;
|
|
field->value = value;
|
|
object->fields.Add(field);
|
|
}
|
|
|
|
Ptr<JsonNode> GetJsonObjectField(Ptr<JsonObject> 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<JsonNode> FindJsonObjectField(Ptr<JsonObject> object, const WString& name)
|
|
{
|
|
for (auto field : object->fields)
|
|
{
|
|
if (field->name.value == name)
|
|
{
|
|
return field->value;
|
|
}
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
WString GetJsonString(Ptr<JsonNode> node)
|
|
{
|
|
auto stringNode = node.Cast<JsonString>();
|
|
CHECK_ERROR(stringNode, L"JSON string is expected.");
|
|
return stringNode->content.value;
|
|
}
|
|
|
|
WString GetJsonNumber(Ptr<JsonNode> node)
|
|
{
|
|
auto numberNode = node.Cast<JsonNumber>();
|
|
CHECK_ERROR(numberNode, L"JSON number is expected.");
|
|
return numberNode->content.value;
|
|
}
|
|
|
|
Ptr<JsonNode> CreateUnknownTuple(const WString& keyword, Ptr<JsonNode> value)
|
|
{
|
|
auto array = CreateJsonArray();
|
|
array->items.Add(CreateJsonString(keyword));
|
|
array->items.Add(value);
|
|
return Ptr<JsonNode>(array);
|
|
}
|
|
|
|
template<typename T>
|
|
bool TrySerializeNumberPrimitive(const Value& value, const WString& keyword, Ptr<JsonNode>& result)
|
|
{
|
|
auto primitive = __vwsn::UnboxWeak<Nullable<T>>(value);
|
|
if (primitive)
|
|
{
|
|
result = CreateUnknownTuple(keyword, CreateJsonNumber(__vwsn::ToString(primitive.Value())));
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
template<typename T>
|
|
bool TrySerializeStringPrimitive(const Value& value, const WString& keyword, Ptr<JsonNode>& result)
|
|
{
|
|
auto primitive = __vwsn::UnboxWeak<Nullable<T>>(value);
|
|
if (primitive)
|
|
{
|
|
result = CreateUnknownTuple(keyword, CreateJsonString(__vwsn::ToString(primitive.Value())));
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
Ptr<JsonNode> SerializeCollection(const WString& keyword, Ptr<IValueEnumerable> 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<JsonNode>(object);
|
|
}
|
|
|
|
Ptr<JsonNode> SerializeMap(Ptr<IValueReadonlyDictionary> 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<JsonNode>(object);
|
|
}
|
|
|
|
Ptr<JsonNode> TrySerializeCollectionTypes(const Value& value, const RpcJsonSerializeCallback& rpcjson_Serialize)
|
|
{
|
|
if (auto observableList = __vwsn::UnboxWeak<Ptr<IValueObservableList>>(value))
|
|
{
|
|
return SerializeCollection(WString::Unmanaged(L"oblist"), observableList, rpcjson_Serialize);
|
|
}
|
|
if (auto dictionary = __vwsn::UnboxWeak<Ptr<IValueDictionary>>(value))
|
|
{
|
|
return SerializeMap(dictionary, rpcjson_Serialize);
|
|
}
|
|
if (auto readonlyDictionary = __vwsn::UnboxWeak<Ptr<IValueReadonlyDictionary>>(value))
|
|
{
|
|
return SerializeMap(readonlyDictionary, rpcjson_Serialize);
|
|
}
|
|
if (auto list = __vwsn::UnboxWeak<Ptr<IValueList>>(value))
|
|
{
|
|
return SerializeCollection(WString::Unmanaged(L"list"), list, rpcjson_Serialize);
|
|
}
|
|
if (auto readonlyList = __vwsn::UnboxWeak<Ptr<IValueReadonlyList>>(value))
|
|
{
|
|
return SerializeCollection(WString::Unmanaged(L"list"), readonlyList, rpcjson_Serialize);
|
|
}
|
|
if (auto enumerable = __vwsn::UnboxWeak<Ptr<IValueEnumerable>>(value))
|
|
{
|
|
return SerializeCollection(WString::Unmanaged(L"list"), enumerable, rpcjson_Serialize);
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
Ptr<JsonNode> TrySerializeRpcTypes(const Value& value)
|
|
{
|
|
if (auto ref = __vwsn::UnboxWeak<Nullable<RpcObjectReference>>(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<JsonNode>(object);
|
|
}
|
|
if (auto exception = __vwsn::UnboxWeak<Nullable<RpcException>>(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<JsonNode>(object);
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
Value DeserializeList(Ptr<JsonObject> object, bool observable, const RpcJsonDeserializeCallback& rpcjson_Deserialize)
|
|
{
|
|
auto values = GetJsonObjectField(object, WString::Unmanaged(L"values")).Cast<JsonArray>();
|
|
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<JsonObject> object, const RpcJsonDeserializeCallback& rpcjson_Deserialize)
|
|
{
|
|
auto values = GetJsonObjectField(object, WString::Unmanaged(L"values")).Cast<JsonArray>();
|
|
CHECK_ERROR(values, L"JSON array is expected.");
|
|
auto result = IValueDictionary::Create();
|
|
for (auto item : values->items)
|
|
{
|
|
auto pair = item.Cast<JsonArray>();
|
|
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<JsonObject> object, const WString& keyword)
|
|
{
|
|
if (keyword == L"system::RpcObjectReference")
|
|
{
|
|
return BoxRpcObjectReference(RpcObjectReference{
|
|
__vwsn::Parse<vint>(GetJsonNumber(GetJsonObjectField(object, WString::Unmanaged(L"clientId")))),
|
|
__vwsn::Parse<vint>(GetJsonNumber(GetJsonObjectField(object, WString::Unmanaged(L"objectId")))),
|
|
__vwsn::Parse<vint>(GetJsonNumber(GetJsonObjectField(object, WString::Unmanaged(L"typeId")))),
|
|
});
|
|
}
|
|
if (keyword == L"system::RpcException")
|
|
{
|
|
return BoxRpcException(RpcException{
|
|
GetJsonString(GetJsonObjectField(object, WString::Unmanaged(L"message"))),
|
|
});
|
|
}
|
|
return {};
|
|
}
|
|
}
|
|
|
|
Ptr<JsonNode> JsonSerializePredefinedTypes(const Value& value, const RpcJsonSerializeCallback& rpcjson_Serialize)
|
|
{
|
|
if (value.IsNull())
|
|
{
|
|
return CreateJsonLiteral(JsonLiteralValue::Null);
|
|
}
|
|
|
|
if (auto primitive = __vwsn::UnboxWeak<Nullable<bool>>(value))
|
|
{
|
|
return CreateJsonLiteral(primitive.Value() ? JsonLiteralValue::True : JsonLiteralValue::False);
|
|
}
|
|
|
|
if (auto primitive = __vwsn::UnboxWeak<Nullable<WString>>(value))
|
|
{
|
|
return CreateJsonString(primitive.Value());
|
|
}
|
|
|
|
Ptr<JsonNode> result;
|
|
if (TrySerializeNumberPrimitive<vuint8_t>(value, WString::Unmanaged(L"UInt8"), result)) return result;
|
|
if (TrySerializeNumberPrimitive<vuint16_t>(value, WString::Unmanaged(L"UInt16"), result)) return result;
|
|
if (TrySerializeNumberPrimitive<vuint32_t>(value, WString::Unmanaged(L"UInt32"), result)) return result;
|
|
if (TrySerializeNumberPrimitive<vuint64_t>(value, WString::Unmanaged(L"UInt64"), result)) return result;
|
|
if (TrySerializeNumberPrimitive<vint8_t>(value, WString::Unmanaged(L"Int8"), result)) return result;
|
|
if (TrySerializeNumberPrimitive<vint16_t>(value, WString::Unmanaged(L"Int16"), result)) return result;
|
|
if (TrySerializeNumberPrimitive<vint32_t>(value, WString::Unmanaged(L"Int32"), result)) return result;
|
|
if (TrySerializeNumberPrimitive<vint64_t>(value, WString::Unmanaged(L"Int64"), result)) return result;
|
|
if (TrySerializeNumberPrimitive<float>(value, WString::Unmanaged(L"Single"), result)) return result;
|
|
if (TrySerializeNumberPrimitive<double>(value, WString::Unmanaged(L"Double"), result)) return result;
|
|
if (TrySerializeStringPrimitive<wchar_t>(value, WString::Unmanaged(L"Char"), result)) return result;
|
|
if (TrySerializeStringPrimitive<DateTime>(value, WString::Unmanaged(L"DateTime"), result)) return result;
|
|
if (TrySerializeStringPrimitive<Locale>(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<Ptr<JsonNode>>(value);
|
|
if (!node)
|
|
{
|
|
return {};
|
|
}
|
|
|
|
if (auto literal = node.Cast<JsonLiteral>())
|
|
{
|
|
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<JsonString>())
|
|
{
|
|
return BoxValue(stringNode->content.value);
|
|
}
|
|
|
|
if (auto numberNode = node.Cast<JsonNumber>())
|
|
{
|
|
return BoxValue(numberNode->content.value);
|
|
}
|
|
|
|
if (auto array = node.Cast<JsonArray>())
|
|
{
|
|
if (array->items.Count() == 2)
|
|
{
|
|
if (auto keywordNode = array->items[0].Cast<JsonString>())
|
|
{
|
|
auto keyword = keywordNode->content.value;
|
|
auto item = array->items[1];
|
|
if (keyword == L"UInt8") return BoxValue(__vwsn::Parse<vuint8_t>(GetJsonNumber(item)));
|
|
if (keyword == L"UInt16") return BoxValue(__vwsn::Parse<vuint16_t>(GetJsonNumber(item)));
|
|
if (keyword == L"UInt32") return BoxValue(__vwsn::Parse<vuint32_t>(GetJsonNumber(item)));
|
|
if (keyword == L"UInt64") return BoxValue(__vwsn::Parse<vuint64_t>(GetJsonNumber(item)));
|
|
if (keyword == L"Int8") return BoxValue(__vwsn::Parse<vint8_t>(GetJsonNumber(item)));
|
|
if (keyword == L"Int16") return BoxValue(__vwsn::Parse<vint16_t>(GetJsonNumber(item)));
|
|
if (keyword == L"Int32") return BoxValue(__vwsn::Parse<vint32_t>(GetJsonNumber(item)));
|
|
if (keyword == L"Int64") return BoxValue(__vwsn::Parse<vint64_t>(GetJsonNumber(item)));
|
|
if (keyword == L"Single") return BoxValue(__vwsn::Parse<float>(GetJsonNumber(item)));
|
|
if (keyword == L"Double") return BoxValue(__vwsn::Parse<double>(GetJsonNumber(item)));
|
|
if (keyword == L"Char") return BoxValue(__vwsn::Parse<wchar_t>(GetJsonString(item)));
|
|
if (keyword == L"DateTime") return BoxValue(__vwsn::Parse<DateTime>(GetJsonString(item)));
|
|
if (keyword == L"Locale") return BoxValue(__vwsn::Parse<Locale>(GetJsonString(item)));
|
|
}
|
|
}
|
|
|
|
auto result = IValueList::Create();
|
|
for (auto item : array->items)
|
|
{
|
|
result->Add(rpcjson_Deserialize(item));
|
|
}
|
|
return BoxValue(result);
|
|
}
|
|
|
|
if (auto object = node.Cast<JsonObject>())
|
|
{
|
|
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<IRpcWrapperBase*>(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<WString, vint>& _idMap)
|
|
{
|
|
CopyFrom(idMap, _idMap);
|
|
}
|
|
|
|
void RpcLifecycleBase::SetSerializer(Ptr<IRpcSerializer> _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<RpcWrapperTracker>();
|
|
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<IValueObservableList*>(obj)) return RpcTypeId_IValueObservableList;
|
|
if (dynamic_cast<IValueDictionary*>(obj)) return RpcTypeId_IValueDictionary;
|
|
if (dynamic_cast<IValueArray*>(obj)) return RpcTypeId_IValueArray;
|
|
if (dynamic_cast<IValueList*>(obj)) return RpcTypeId_IValueList;
|
|
if (dynamic_cast<IValueReadonlyList*>(obj)) return RpcTypeId_IValueReadonlyList;
|
|
if (dynamic_cast<IValueEnumerator*>(obj)) return RpcTypeId_IValueEnumerator;
|
|
if (dynamic_cast<IValueEnumerable*>(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<IValueObservableList*>(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<DescriptableObject*>(obj))
|
|
{
|
|
Ptr<RpcLocalObjectTracker> tracker;
|
|
if (auto trackerObj = descriptable->GetInternalProperty(InternalProperty_LocalObjectTracker))
|
|
{
|
|
tracker = trackerObj.Cast<RpcLocalObjectTracker>();
|
|
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<IValueObservableList*>(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<DescriptableObject*>(rawPtr))
|
|
{
|
|
if (auto trackerObj = descriptable->GetInternalProperty(InternalProperty_LocalObjectTracker))
|
|
{
|
|
auto tracker = trackerObj.Cast<RpcLocalObjectTracker>();
|
|
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<RpcWrapperTracker>();
|
|
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<IDescriptable> RpcLifecycleBase::CreateCallerProxy(RpcObjectReference ref, IRpcSerializer* serializer)
|
|
{
|
|
#define ERROR_MESSAGE_PREFIX L"vl::rpc_controller::RpcLifecycleBase::CreateCallerProxy(RpcObjectReference)#"
|
|
IRpcLifecycle* lc = this;
|
|
Ptr<IRpcWrapperBase> 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<IDescriptable*>(wrapper.Obj());
|
|
CHECK_ERROR(descriptable, ERROR_MESSAGE_PREFIX L"Wrapper does not implement IDescriptable.");
|
|
auto root = dynamic_cast<DescriptableObject*>(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<IDescriptable> 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<IDescriptable> 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<IDescriptable> RpcLifecycleBase::RefToPtr(RpcObjectReference ref)
|
|
{
|
|
return RefToPtr(ref, serializer.Obj());
|
|
}
|
|
|
|
Ptr<IDescriptable> 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<IDescriptable*>(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<IDescriptable> obj)
|
|
{
|
|
#define ERROR_MESSAGE_PREFIX L"vl::rpc_controller::RpcLifecycleBase::PtrToRef(Ptr<reflection::IDescriptable>)#"
|
|
CHECK_ERROR(obj, ERROR_MESSAGE_PREFIX L"A value is required.");
|
|
|
|
if (auto descObj = dynamic_cast<DescriptableObject*>(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<DescriptableObject*>(obj.Obj()))
|
|
{
|
|
if (auto trackerObj = descObj->GetInternalProperty(InternalProperty_LocalObjectTracker))
|
|
{
|
|
auto tracker = trackerObj.Cast<RpcLocalObjectTracker>();
|
|
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<IValueType::TypedBox<RpcObjectReference>>();
|
|
}
|
|
|
|
RpcObjectReference GetRpcObjectReference(const Value& value)
|
|
{
|
|
auto boxed = value.GetBoxedValue().Cast<IValueType::TypedBox<RpcObjectReference>>();
|
|
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<IRpcWrapperBase*>(obj)) return wrapper;
|
|
return obj->SafeAggregationCast<IRpcWrapperBase>();
|
|
}
|
|
|
|
template<typename TInterface>
|
|
TInterface* CastRpcInterface(IDescriptable* obj)
|
|
{
|
|
if (!obj) return nullptr;
|
|
if (auto proxy = dynamic_cast<TInterface*>(obj)) return proxy;
|
|
return obj->SafeAggregationCast<TInterface>();
|
|
}
|
|
|
|
template<typename K, typename V>
|
|
bool ContainsKey(const Dictionary<K, V>& xs, const K& key)
|
|
{
|
|
return xs.Keys().Contains(key);
|
|
}
|
|
|
|
template<typename TWrapper, typename TInterface>
|
|
Ptr<TInterface> CreateTrackedProxy(IRpcLifecycle* lc, RpcObjectReference ref, IRpcSerializer* serializer)
|
|
{
|
|
auto obj = [&]()
|
|
{
|
|
if (auto lifecycle = dynamic_cast<RpcLifecycleBase*>(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<TInterface>(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<const DescriptableObject*, bool>& visited);
|
|
extern Value RpcBoxValueByvalInternal(const Value& trivial, IRpcLifecycle* lc, Dictionary<const DescriptableObject*, bool>& visited);
|
|
extern Value RpcUnboxValueByvalInternal(const Value& serializable, IRpcLifecycle* lc, Dictionary<const DescriptableObject*, bool>& 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<IValueEnumerator> RpcByrefEnumerable::CreateEnumerator()
|
|
{
|
|
return CreateTrackedProxy<RpcByrefEnumerator, IValueEnumerator>(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<IValueEnumerator> RpcByrefReadonlyList::CreateEnumerator()
|
|
{
|
|
return CreateTrackedProxy<RpcByrefEnumerator, IValueEnumerator>(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<IValueEnumerator> 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<IValueEnumerator> RpcByrefArray::CreateEnumerator()
|
|
{
|
|
return CreateTrackedProxy<RpcByrefEnumerator, IValueEnumerator>(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<IValueEnumerator> RpcByrefObservableList::CreateEnumerator()
|
|
{
|
|
return CreateTrackedProxy<RpcByrefEnumerator, IValueEnumerator>(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<IValueReadonlyList> RpcByrefDictionary::GetKeys()
|
|
{
|
|
return CreateTrackedProxy<RpcByrefReadonlyList, IValueReadonlyList>(lifecycle, GetRemoteListOps(lifecycle, ref)->DictGetKeys(ref), serializer);
|
|
}
|
|
|
|
Ptr<IValueReadonlyList> RpcByrefDictionary::GetValues()
|
|
{
|
|
return CreateTrackedProxy<RpcByrefReadonlyList, IValueReadonlyList>(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<IValueEnumerator> enumerator;
|
|
if (auto xs = Ptr(obj.Obj()->SafeAggregationCast<IValueEnumerable>()))
|
|
{
|
|
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<IValueEnumerator>());
|
|
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<IValueEnumerator>());
|
|
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<IValueReadonlyList>()))
|
|
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<IValueReadonlyList>()))
|
|
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<IValueArray>()))
|
|
{
|
|
array->Set(index, trivial);
|
|
return;
|
|
}
|
|
if (auto list = Ptr(obj.Obj()->SafeAggregationCast<IValueList>()))
|
|
{
|
|
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<IValueList>()))
|
|
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<IValueList>()))
|
|
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<IValueArray>()))
|
|
{
|
|
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<IValueList>()))
|
|
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<IValueArray>()))
|
|
{
|
|
array->Resize(0);
|
|
return;
|
|
}
|
|
if (auto list = Ptr(obj.Obj()->SafeAggregationCast<IValueList>()))
|
|
{
|
|
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<IValueReadonlyList>()))
|
|
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<IValueReadonlyList>()))
|
|
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<IValueReadonlyDictionary>());
|
|
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<IValueReadonlyDictionary>());
|
|
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<IValueDictionary>());
|
|
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<IValueDictionary>());
|
|
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<IValueDictionary>());
|
|
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<IValueReadonlyDictionary>());
|
|
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<IValueReadonlyDictionary>());
|
|
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<IValueReadonlyDictionary>());
|
|
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<IValueObservableList>());
|
|
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<IDescriptable> trivial, IRpcLifecycle* lc)
|
|
{
|
|
if (!lc) CHECK_FAIL(L"IRpcLifecycle cannot be null.");
|
|
if (!trivial) return {};
|
|
return lc->PtrToRef(trivial);
|
|
}
|
|
|
|
Ptr<IDescriptable> 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<IDescriptable*>(raw))
|
|
{
|
|
return BoxValue(RpcBoxByref(Ptr<IDescriptable>(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<typename TInterface>
|
|
Ptr<TInterface> TryGetValueInterface(const Value& value)
|
|
{
|
|
if (auto raw = value.GetRawPtr())
|
|
{
|
|
return Ptr(dynamic_cast<TInterface*>(raw));
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
Value RpcCopyValueByvalInternal(const Value& trivial, Dictionary<const DescriptableObject*, bool>& visited)
|
|
{
|
|
if (trivial.IsNull()) return trivial;
|
|
if (trivial.GetValueType() == Value::SharedPtr)
|
|
{
|
|
if (auto roDict = TryGetValueInterface<IValueReadonlyDictionary>(trivial))
|
|
{
|
|
auto key = static_cast<const DescriptableObject*>(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<IValueObservableList>(trivial))
|
|
{
|
|
auto key = static_cast<const DescriptableObject*>(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<IValueArray>(trivial))
|
|
{
|
|
auto key = static_cast<const DescriptableObject*>(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<IValueReadonlyList>(trivial))
|
|
{
|
|
auto key = static_cast<const DescriptableObject*>(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<const DescriptableObject*, bool>& visited)
|
|
{
|
|
if (trivial.IsNull()) return trivial;
|
|
if (trivial.GetValueType() == Value::SharedPtr)
|
|
{
|
|
if (auto roDict = TryGetValueInterface<IValueReadonlyDictionary>(trivial))
|
|
{
|
|
auto key = static_cast<const DescriptableObject*>(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<IValueObservableList>(trivial))
|
|
{
|
|
auto key = static_cast<const DescriptableObject*>(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<IValueArray>(trivial))
|
|
{
|
|
auto key = static_cast<const DescriptableObject*>(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<IValueReadonlyList>(trivial))
|
|
{
|
|
auto key = static_cast<const DescriptableObject*>(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<IDescriptable*>(raw))
|
|
{
|
|
auto ref = lc->PtrToRef(Ptr<IDescriptable>(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<const DescriptableObject*, bool> visited;
|
|
return RpcCopyValueByvalInternal(trivial, visited);
|
|
}
|
|
|
|
Value RpcBoxByval(Ptr<IDescriptable> 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<const DescriptableObject*, bool> visited;
|
|
return RpcBoxValueByvalInternal(trivial, lc, visited);
|
|
}
|
|
|
|
namespace
|
|
{
|
|
Value RpcUnboxValueByvalInternal(const Value& serializable, IRpcLifecycle* lc, Dictionary<const DescriptableObject*, bool>& 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<IValueReadonlyDictionary>(serializable))
|
|
{
|
|
auto key = static_cast<const DescriptableObject*>(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<IValueObservableList>(serializable))
|
|
{
|
|
auto key = static_cast<const DescriptableObject*>(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<IValueArray>(serializable))
|
|
{
|
|
auto key = static_cast<const DescriptableObject*>(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<IValueReadonlyList>(serializable))
|
|
{
|
|
auto key = static_cast<const DescriptableObject*>(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<IDescriptable> RpcUnboxByval(const Value& serializable, IRpcLifecycle* lc)
|
|
{
|
|
if (!lc) CHECK_FAIL(L"IRpcLifecycle cannot be null.");
|
|
if (serializable.IsNull()) return nullptr;
|
|
Dictionary<const DescriptableObject*, bool> visited;
|
|
auto trivial = RpcUnboxValueByvalInternal(serializable, lc, visited);
|
|
if (auto raw = trivial.GetRawPtr())
|
|
{
|
|
if (auto obj = dynamic_cast<IDescriptable*>(raw))
|
|
{
|
|
return Ptr<IDescriptable>(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<IValueType::TypedBox<RpcException>>())
|
|
{
|
|
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<RpcException>(exceptions->Get(key));
|
|
message += itow(UnboxValue<vint>(key)) + L":" + exception.message + L";";
|
|
}
|
|
throw Exception(message);
|
|
}
|
|
}
|
|
}
|
|
|