/***********************************************************************
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::IRpcJsonMessageDispatcher::RequestType, system::IRpcJsonMessageDispatcher::RequestType)
			IMPL_TYPE_INFO_RENAME(vl::rpc_controller::IRpcJsonMessageDispatcher, system::IRpcJsonMessageDispatcher)
			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_ENUM_ITEM(vl::rpc_controller::IRpcJsonMessageDispatcher::RequestType)
				ENUM_CLASS_ITEM(Direct)
				ENUM_CLASS_ITEM(Broadcast)
				ENUM_CLASS_ITEM(BroadcastAndDrop)
			END_ENUM_ITEM(vl::rpc_controller::IRpcJsonMessageDispatcher::RequestType)

			BEGIN_INTERFACE_MEMBER(vl::rpc_controller::IRpcJsonMessageDispatcher)
				CLASS_MEMBER_METHOD(AllocateRequestId, NO_PARAMETER)
				CLASS_MEMBER_METHOD(OnJsonRequest, { L"message" _ L"requestType" })
			END_INTERFACE_MEMBER(vl::rpc_controller::IRpcJsonMessageDispatcher)

			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(ArrayResize, { L"ref" _ L"size" })

				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" })
			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(ObjectOps)
				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(Initialize, NO_PARAMETER)
				CLASS_MEMBER_METHOD(DeclareLocalService, { L"ref" })
				CLASS_MEMBER_METHOD(BroadcastFromClient_ObjectEventOps, { L"selfClientId" })
				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_METHOD(Initialize, 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(RegisterLocalService, { L"typeId" _ L"service" })
				CLASS_MEMBER_METHOD(DeclareRemoteService, { L"ref" })
				CLASS_MEMBER_METHOD(GetTypeIdFromName, { L"typeName" })
				CLASS_MEMBER_METHOD(RequestService, { L"typeName" })
				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 collections;
		using namespace reflection;
		using namespace reflection::description;

		namespace
		{
#ifndef VCZH_WORKFLOW_RPC_OBJECT_REFERENCE_VALUE_HELPERS
#define VCZH_WORKFLOW_RPC_OBJECT_REFERENCE_VALUE_HELPERS
			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;
			}
#endif

			bool IsNullRpcObjectReference(RpcObjectReference ref)
			{
				return ref.clientId == RpcClientId_Invalid
					&& ref.objectId == RpcObjectId_Invalid
					&& ref.typeId == RpcTypeId_NotFound;
			}

			template<typename K, typename V>
			bool ContainsKey(const Dictionary<K, V>& xs, const K& key)
			{
				return xs.Keys().Contains(key);
			}

			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 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 BoxValue(obj);
				}

				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;
			}
		}

		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));
			}
		}

		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);
		}

		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.");
			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);
		}

		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);
		}
	}
}


/***********************************************************************
.\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)
		{
			objectCallback = _objectCallback;
			eventCallback = _eventCallback;
		}

		IRpcObjectOps* RpcControllerDefault::GetObjectOps()
		{
			return objectCallback.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\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 listEventOps = Ptr(new RpcCallerListEventOps(
						this->GetDispatcher()->BroadcastFromClient_ObjectEventOps(this->GetClientId()),
						serializer.Obj()
						));
					listEventOps->OnItemChanged(ref, index, oldCount, newCount);
				});
				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
		}

		RpcObjectReference RpcLifecycleBase::CreateLocalObject(Ptr<IDescriptable> obj, RpcObjectReference ref)
		{
#define ERROR_MESSAGE_PREFIX L"vl::rpc_controller::RpcLifecycleBase::CreateLocalObject(Ptr<reflection::IDescriptable>, RpcObjectReference)#"
			CHECK_ERROR(ref.clientId == clientId, ERROR_MESSAGE_PREFIX L"Ref is not local.");
			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());
			if (nextObjectId < ref.objectId)
			{
				nextObjectId = ref.objectId;
			}
			return 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);
			}
			registeredLocalServices.Clear();
			registeredRemoteServices.Clear();
			controller.Finalize();
		}

		void RpcLifecycleBase::Initialize()
		{
			if (!initialized)
			{
				GetDispatcher()->Initialize();
				initialized = true;
			}
		}

		vint RpcLifecycleBase::GetClientId()
		{
			return clientId;
		}

		RpcControllerDefault* RpcLifecycleBase::GetController()
		{
			return &controller;
		}

		const RpcLocalServiceMap& RpcLifecycleBase::GetRegisteredLocalServices()
		{
			return registeredLocalServices;
		}

		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::RegisterLocalService(vint typeId, Ptr<IDescriptable> service)
		{
#define ERROR_MESSAGE_PREFIX L"vl::rpc_controller::RpcLifecycleBase::RegisterLocalService(vint, Ptr<IDescriptable>)#"
			CHECK_ERROR(service, ERROR_MESSAGE_PREFIX L"Service is required.");
			if (initialized)
			{
				throw Exception(ERROR_MESSAGE_PREFIX L"RegisterLocalService cannot be called after Initialize.");
			}
			if (registeredLocalServices.Keys().Contains(typeId))
			{
				throw Exception(ERROR_MESSAGE_PREFIX L"Service is already registered.");
			}

			auto ref = CreateLocalObject(service, RpcObjectReference{ clientId, typeId, typeId });
			LocalObjectHold(ref, clientId);
			registeredLocalServices.Set(typeId, service);
			GetDispatcher()->DeclareLocalService(ref);
#undef ERROR_MESSAGE_PREFIX
		}

		void RpcLifecycleBase::DeclareRemoteService(RpcObjectReference ref)
		{
			registeredRemoteServices.Set(ref.typeId, ref);
		}

		vint RpcLifecycleBase::GetTypeIdFromName(WString typeName)
		{
			auto typeIndex = idMap.Keys().IndexOf(typeName);
			if (typeIndex == -1)
			{
				return RpcTypeId_NotFound;
			}
			return idMap.Values()[typeIndex];
		}

		Ptr<IDescriptable> RpcLifecycleBase::RequestService(WString typeName)
		{
			auto typeId = GetTypeIdFromName(typeName);
			if (typeId == RpcTypeId_NotFound)
			{
				return nullptr;
			}

			if (auto index = registeredLocalServices.Keys().IndexOf(typeId); index != -1)
			{
				return registeredLocalServices.Values()[index];
			}

			if (auto index = registeredRemoteServices.Keys().IndexOf(typeId); index != -1)
			{
				return RefToPtr(registeredRemoteServices.Values()[index]);
			}

			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).");
			return CreateLocalObject(obj, RpcObjectReference{ clientId, ++nextObjectId, typeId });
#undef ERROR_MESSAGE_PREFIX
		}
	}
}


/***********************************************************************
.\RPC\WFLIBRARYRPCWRAPPERS.CPP
***********************************************************************/

namespace vl
{
	using namespace collections;

	namespace rpc_controller
	{
		using namespace reflection;
		using namespace reflection::description;

		namespace
		{
#ifndef VCZH_WORKFLOW_RPC_OBJECT_REFERENCE_VALUE_HELPERS
#define VCZH_WORKFLOW_RPC_OBJECT_REFERENCE_VALUE_HELPERS
			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;
			}
#endif

			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 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);
			}

			Ptr<IRpcListOps> GetRemoteListOps(IRpcLifecycle* lc, RpcObjectReference ref, IRpcSerializer* serializer)
			{
				return Ptr(new RpcCallerListOps(lc->GetDispatcher()->SendToClient_ObjectOps(ref.clientId), serializer));
			}

			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;
			}

			template<typename ...TArgs>
			Ptr<IValueArray> CreateRpcArguments(TArgs&& ...args)
			{
				auto arguments = IValueArray::Create();
				arguments->Resize(sizeof...(TArgs));
				vint index = 0;
				((arguments->Set(index++, std::forward<TArgs>(args))), ...);
				return arguments;
			}

			Value ReadMethodResult(IRpcSerializer* serializer, const Value& value)
			{
				auto deserialized = DeserializeValue(serializer, value);
				ReadMethodException(deserialized);
				return deserialized;
			}

			Value InvokeListMethod(IRpcObjectOps* objectOps, IRpcSerializer* serializer, RpcObjectReference ref, vint methodId, Ptr<IValueArray> arguments)
			{
				auto result = objectOps->InvokeMethod(ref, methodId, arguments);
				return ReadMethodResult(serializer, result);
			}

			bool IsRpcListMethodId(vint methodId)
			{
				switch (methodId)
				{
				case RpcMethodId_IValueEnumerable_CreateEnumerator:
				case RpcMethodId_IValueEnumerator_Next:
				case RpcMethodId_IValueEnumerator_GetCurrent:
				case RpcMethodId_IValueReadonlyList_GetCount:
				case RpcMethodId_IValueReadonlyList_Get:
				case RpcMethodId_IValueList_Set:
				case RpcMethodId_IValueList_Add:
				case RpcMethodId_IValueList_Insert:
				case RpcMethodId_IValueList_RemoveAt:
				case RpcMethodId_IValueList_Clear:
				case RpcMethodId_IValueReadonlyList_Contains:
				case RpcMethodId_IValueReadonlyList_IndexOf:
				case RpcMethodId_IValueReadonlyDictionary_GetCount:
				case RpcMethodId_IValueReadonlyDictionary_Get:
				case RpcMethodId_IValueDictionary_Set:
				case RpcMethodId_IValueDictionary_Remove:
				case RpcMethodId_IValueDictionary_Clear:
				case RpcMethodId_IValueReadonlyDictionary_ContainsKey:
				case RpcMethodId_IValueReadonlyDictionary_GetKeys:
				case RpcMethodId_IValueReadonlyDictionary_GetValues:
				case RpcMethodId_IValueArray_Resize:
					return true;
				default:
					return false;
				}
			}

			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 BoxValue(obj);
				}

				return serializable;
			}

		}

/***********************************************************************
* 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(GetRemoteListOps(lifecycle, ref, serializer)->EnumGetCurrent(ref), lifecycle);
		}

		vint RpcByrefEnumerator::GetIndex()
		{
			return index;
		}

		bool RpcByrefEnumerator::Next()
		{
			if (GetRemoteListOps(lifecycle, ref, serializer)->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, serializer)->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, serializer)->EnumCreate(ref), serializer);
		}

		vint RpcByrefReadonlyList::GetCount()
		{
			return GetRemoteListOps(lifecycle, ref, serializer)->ListGetCount(ref);
		}

		Value RpcByrefReadonlyList::Get(vint index)
		{
			return RpcUnboxValueByref(GetRemoteListOps(lifecycle, ref, serializer)->ListGet(ref, index), lifecycle);
		}

		bool RpcByrefReadonlyList::Contains(const Value& value)
		{
			return GetRemoteListOps(lifecycle, ref, serializer)->ListContains(ref, SerializeValue(serializer, RpcBoxValueByref(value, lifecycle)));
		}

		vint RpcByrefReadonlyList::IndexOf(const Value& value)
		{
			return GetRemoteListOps(lifecycle, ref, serializer)->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, serializer)->ListSet(ref, index, SerializeValue(serializer, RpcBoxValueByref(value, lifecycle)));
		}

		vint RpcByrefList::Add(const Value& value)
		{
			return GetRemoteListOps(lifecycle, ref, serializer)->ListAdd(ref, SerializeValue(serializer, RpcBoxValueByref(value, lifecycle)));
		}

		vint RpcByrefList::Insert(vint index, const Value& value)
		{
			return GetRemoteListOps(lifecycle, ref, serializer)->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, serializer)->ListRemoveAt(ref, index);
		}

		bool RpcByrefList::RemoveAt(vint index)
		{
			return GetRemoteListOps(lifecycle, ref, serializer)->ListRemoveAt(ref, index);
		}

		void RpcByrefList::Clear()
		{
			GetRemoteListOps(lifecycle, ref, serializer)->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, serializer)->EnumCreate(ref), serializer);
		}

		vint RpcByrefArray::GetCount()
		{
			return GetRemoteListOps(lifecycle, ref, serializer)->ListGetCount(ref);
		}

		Value RpcByrefArray::Get(vint index)
		{
			return RpcUnboxValueByref(GetRemoteListOps(lifecycle, ref, serializer)->ListGet(ref, index), lifecycle);
		}

		bool RpcByrefArray::Contains(const Value& value)
		{
			return GetRemoteListOps(lifecycle, ref, serializer)->ListContains(ref, SerializeValue(serializer, RpcBoxValueByref(value, lifecycle)));
		}

		vint RpcByrefArray::IndexOf(const Value& value)
		{
			return GetRemoteListOps(lifecycle, ref, serializer)->ListIndexOf(ref, SerializeValue(serializer, RpcBoxValueByref(value, lifecycle)));
		}

		void RpcByrefArray::Set(vint index, const Value& value)
		{
			GetRemoteListOps(lifecycle, ref, serializer)->ListSet(ref, index, SerializeValue(serializer, RpcBoxValueByref(value, lifecycle)));
		}

		void RpcByrefArray::Resize(vint size)
		{
			GetRemoteListOps(lifecycle, ref, serializer)->ArrayResize(ref, size);
		}

/***********************************************************************
* 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, serializer)->EnumCreate(ref), serializer);
		}

		vint RpcByrefObservableList::GetCount()
		{
			return GetRemoteListOps(lifecycle, ref, serializer)->ListGetCount(ref);
		}

		Value RpcByrefObservableList::Get(vint index)
		{
			return RpcUnboxValueByref(GetRemoteListOps(lifecycle, ref, serializer)->ListGet(ref, index), lifecycle);
		}

		bool RpcByrefObservableList::Contains(const Value& value)
		{
			return GetRemoteListOps(lifecycle, ref, serializer)->ListContains(ref, SerializeValue(serializer, RpcBoxValueByref(value, lifecycle)));
		}

		vint RpcByrefObservableList::IndexOf(const Value& value)
		{
			return GetRemoteListOps(lifecycle, ref, serializer)->ListIndexOf(ref, SerializeValue(serializer, RpcBoxValueByref(value, lifecycle)));
		}

		void RpcByrefObservableList::Set(vint index, const Value& value)
		{
			GetRemoteListOps(lifecycle, ref, serializer)->ListSet(ref, index, SerializeValue(serializer, RpcBoxValueByref(value, lifecycle)));
		}

		vint RpcByrefObservableList::Add(const Value& value)
		{
			return GetRemoteListOps(lifecycle, ref, serializer)->ListAdd(ref, SerializeValue(serializer, RpcBoxValueByref(value, lifecycle)));
		}

		vint RpcByrefObservableList::Insert(vint index, const Value& value)
		{
			return GetRemoteListOps(lifecycle, ref, serializer)->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, serializer)->ListRemoveAt(ref, index);
		}

		bool RpcByrefObservableList::RemoveAt(vint index)
		{
			return GetRemoteListOps(lifecycle, ref, serializer)->ListRemoveAt(ref, index);
		}

		void RpcByrefObservableList::Clear()
		{
			GetRemoteListOps(lifecycle, ref, serializer)->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, serializer)->DictGetKeys(ref), serializer);
		}

		Ptr<IValueReadonlyList> RpcByrefDictionary::GetValues()
		{
			return CreateTrackedProxy<RpcByrefReadonlyList, IValueReadonlyList>(lifecycle, GetRemoteListOps(lifecycle, ref, serializer)->DictGetValues(ref), serializer);
		}

		vint RpcByrefDictionary::GetCount()
		{
			return GetRemoteListOps(lifecycle, ref, serializer)->DictGetCount(ref);
		}

		Value RpcByrefDictionary::Get(const Value& key)
		{
			auto serializedKey = SerializeValue(serializer, RpcBoxValueByref(key, lifecycle));
			auto serializedValue = GetRemoteListOps(lifecycle, ref, serializer)->DictGet(ref, serializedKey);
			return RpcUnboxValueByref(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, serializer)->DictSet(ref, serializedKey, serializedValue);
		}

		bool RpcByrefDictionary::Remove(const Value& key)
		{
			return GetRemoteListOps(lifecycle, ref, serializer)->DictRemove(ref, SerializeValue(serializer, RpcBoxValueByref(key, lifecycle)));
		}

		void RpcByrefDictionary::Clear()
		{
			GetRemoteListOps(lifecycle, ref, serializer)->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
			{
				throw Exception(L"RpcCalleeListOps::EnumCreate cannot find the target collection.");
			}

			return lifecycle->PtrToRef(enumerator);
		}

		bool RpcCalleeListOps::EnumNext(RpcObjectReference enumerator)
		{
			auto obj = lifecycle->RefToPtr(enumerator);
			auto e = Ptr(obj.Obj()->SafeAggregationCast<IValueEnumerator>());
			if (!e) throw Exception(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>());
			if (!e) throw Exception(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();
			throw Exception(L"RpcCalleeListOps::ListGetCount cannot find the target list.");
		}

		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));
			throw Exception(L"RpcCalleeListOps::ListGet cannot find the target list.");
		}

		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;
			}
			throw Exception(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);
			throw Exception(L"RpcCalleeListOps::ListAdd cannot find a writable list.");
		}

		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);
			throw Exception(L"RpcCalleeListOps::ListInsert cannot find a writable list.");
		}

		bool RpcCalleeListOps::ListRemoveAt(RpcObjectReference ref, vint index)
		{
			auto obj = lifecycle->RefToPtr(ref);
			if (auto list = Ptr(obj.Obj()->SafeAggregationCast<IValueList>()))
				return list->RemoveAt(index);
			throw Exception(L"RpcCalleeListOps::ListRemoveAt cannot find the target list.");
		}

		void RpcCalleeListOps::ListClear(RpcObjectReference ref)
		{
			auto obj = lifecycle->RefToPtr(ref);
			if (auto list = Ptr(obj.Obj()->SafeAggregationCast<IValueList>()))
			{
				list->Clear();
				return;
			}
			throw Exception(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);
			throw Exception(L"RpcCalleeListOps::ListContains cannot find the target list.");
		}

		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);
			throw Exception(L"RpcCalleeListOps::ListIndexOf cannot find the target list.");
		}

		void RpcCalleeListOps::ArrayResize(RpcObjectReference ref, vint size)
		{
			auto obj = lifecycle->RefToPtr(ref);
			auto array = Ptr(obj.Obj()->SafeAggregationCast<IValueArray>());
			if (!array) throw Exception(L"RpcCalleeListOps::ArrayResize cannot find the target array.");
			array->Resize(size);
		}

		vint RpcCalleeListOps::DictGetCount(RpcObjectReference ref)
		{
			auto obj = lifecycle->RefToPtr(ref);
			auto dict = Ptr(obj.Obj()->SafeAggregationCast<IValueReadonlyDictionary>());
			if (!dict) throw Exception(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>());
			if (!dict) throw Exception(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>());
			if (!dict) throw Exception(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>());
			if (!dict) throw Exception(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>());
			if (!dict) throw Exception(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>());
			if (!dict) throw Exception(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>());
			if (!dict) throw Exception(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>());
			if (!dict) throw Exception(L"RpcCalleeListOps::DictGetValues cannot find the target dictionary.");
			return lifecycle->PtrToRef(dict->GetValues());
		}

/***********************************************************************
* RpcCalleeListEventOps
***********************************************************************/

		RpcCalleeListEventOps::RpcCalleeListEventOps(IRpcLifecycle* lc, IRpcSerializer* _serializer)
			: lifecycle(lc)
			, serializer(_serializer)
		{
			if (!lifecycle) CHECK_FAIL(L"Invalid IRpcLifecycle.");
		}

		Value RpcCalleeListEventOps::OnItemChanged(RpcObjectReference ref, vint index, vint oldCount, vint newCount)
		{
			struct SuppressFlag
			{
				IRpcLifecycle*		lifecycle;
				RpcObjectReference	ref;

				SuppressFlag(IRpcLifecycle* _lifecycle, RpcObjectReference _ref)
					: lifecycle(_lifecycle)
					, ref(_ref)
				{
					lifecycle->GetController()->SetItemChangedSuppressedFlag(ref, true);
				}
				~SuppressFlag()
				{
					lifecycle->GetController()->SetItemChangedSuppressedFlag(ref, false);
				}
			};

			auto obj = lifecycle->RefToPtr(ref);
			auto observable = Ptr(obj.Obj()->SafeAggregationCast<IValueObservableList>());
			CHECK_ERROR(observable, L"RpcCalleeListEventOps::OnItemChanged cannot find the target observable list.");

			RpcEventExceptionMap exceptions;
			{
				SuppressFlag suppressFlag(lifecycle, ref);
				try
				{
					observable->ItemChanged(index, oldCount, newCount);
				}
				catch (const Exception& ex)
				{
					exceptions = IValueDictionary::Create();
					exceptions->Set(BoxValue(lifecycle->GetClientId()), BoxValue(RpcException{ ex.Message() }));
				}
			}
			return SerializeValue(serializer, BoxValue(exceptions));
		}

/***********************************************************************
* RpcCalleeObjectOpsForList
***********************************************************************/

		RpcCalleeObjectOpsForList::RpcCalleeObjectOpsForList(Ptr<RpcCalleeListOps> _listOps, Ptr<IRpcObjectOps> _objectOps, IRpcSerializer* _serializer)
			: listOps(_listOps)
			, objectOps(_objectOps)
			, serializer(_serializer)
		{
#define ERROR_MESSAGE_PREFIX L"vl::rpc_controller::RpcCalleeObjectOpsForList::RpcCalleeObjectOpsForList(...)#"
			CHECK_ERROR(listOps && objectOps, ERROR_MESSAGE_PREFIX L"List ops and object ops are required.");
#undef ERROR_MESSAGE_PREFIX
		}

		Value RpcCalleeObjectOpsForList::InvokeMethod(RpcObjectReference ref, vint methodId, Ptr<IValueArray> arguments)
		{
			if (!IsRpcListMethodId(methodId))
			{
				return objectOps->InvokeMethod(ref, methodId, arguments);
			}

			try
			{
				switch (methodId)
				{
				case RpcMethodId_IValueEnumerable_CreateEnumerator:
					return SerializeValue(serializer, BoxValue(listOps->EnumCreate(ref)));
				case RpcMethodId_IValueEnumerator_Next:
					return SerializeValue(serializer, BoxValue(listOps->EnumNext(ref)));
				case RpcMethodId_IValueEnumerator_GetCurrent:
					return listOps->EnumGetCurrent(ref);
				case RpcMethodId_IValueReadonlyList_GetCount:
					return SerializeValue(serializer, BoxValue(listOps->ListGetCount(ref)));
				case RpcMethodId_IValueReadonlyList_Get:
					return listOps->ListGet(ref, UnboxValue<vint>(DeserializeValue(serializer, arguments->Get(0))));
				case RpcMethodId_IValueList_Set:
					listOps->ListSet(ref, UnboxValue<vint>(DeserializeValue(serializer, arguments->Get(0))), arguments->Get(1));
					return SerializeValue(serializer, Value());
				case RpcMethodId_IValueList_Add:
					return SerializeValue(serializer, BoxValue(listOps->ListAdd(ref, arguments->Get(0))));
				case RpcMethodId_IValueList_Insert:
					return SerializeValue(serializer, BoxValue(listOps->ListInsert(ref, UnboxValue<vint>(DeserializeValue(serializer, arguments->Get(0))), arguments->Get(1))));
				case RpcMethodId_IValueList_RemoveAt:
					return SerializeValue(serializer, BoxValue(listOps->ListRemoveAt(ref, UnboxValue<vint>(DeserializeValue(serializer, arguments->Get(0))))));
				case RpcMethodId_IValueList_Clear:
					listOps->ListClear(ref);
					return SerializeValue(serializer, Value());
				case RpcMethodId_IValueReadonlyList_Contains:
					return SerializeValue(serializer, BoxValue(listOps->ListContains(ref, arguments->Get(0))));
				case RpcMethodId_IValueReadonlyList_IndexOf:
					return SerializeValue(serializer, BoxValue(listOps->ListIndexOf(ref, arguments->Get(0))));
				case RpcMethodId_IValueReadonlyDictionary_GetCount:
					return SerializeValue(serializer, BoxValue(listOps->DictGetCount(ref)));
				case RpcMethodId_IValueReadonlyDictionary_Get:
					return listOps->DictGet(ref, arguments->Get(0));
				case RpcMethodId_IValueDictionary_Set:
					listOps->DictSet(ref, arguments->Get(0), arguments->Get(1));
					return SerializeValue(serializer, Value());
				case RpcMethodId_IValueDictionary_Remove:
					return SerializeValue(serializer, BoxValue(listOps->DictRemove(ref, arguments->Get(0))));
				case RpcMethodId_IValueDictionary_Clear:
					listOps->DictClear(ref);
					return SerializeValue(serializer, Value());
				case RpcMethodId_IValueReadonlyDictionary_ContainsKey:
					return SerializeValue(serializer, BoxValue(listOps->DictContainsKey(ref, arguments->Get(0))));
				case RpcMethodId_IValueReadonlyDictionary_GetKeys:
					return SerializeValue(serializer, BoxValue(listOps->DictGetKeys(ref)));
				case RpcMethodId_IValueReadonlyDictionary_GetValues:
					return SerializeValue(serializer, BoxValue(listOps->DictGetValues(ref)));
				case RpcMethodId_IValueArray_Resize:
					listOps->ArrayResize(ref, UnboxValue<vint>(DeserializeValue(serializer, arguments->Get(0))));
					return SerializeValue(serializer, Value());
				}
			}
			catch (const Exception& ex)
			{
				return SerializeValue(serializer, BoxValue(RpcException{ ex.Message() }));
			}
			CHECK_FAIL(L"Unknown RPC list method id.");
			return {};
		}

		void RpcCalleeObjectOpsForList::EndInvokeMethod(vint slot)
		{
			objectOps->EndInvokeMethod(slot);
		}

		void RpcCalleeObjectOpsForList::ObjectHold(RpcObjectReference ref, vint remoteClientId, bool hold)
		{
			objectOps->ObjectHold(ref, remoteClientId, hold);
		}

/***********************************************************************
* RpcCalleeObjectEventOpsForList
***********************************************************************/

		RpcCalleeObjectEventOpsForList::RpcCalleeObjectEventOpsForList(Ptr<RpcCalleeListEventOps> _listEventOps, Ptr<IRpcObjectEventOps> _objectEventOps, IRpcSerializer* _serializer)
			: listEventOps(_listEventOps)
			, objectEventOps(_objectEventOps)
			, serializer(_serializer)
		{
#define ERROR_MESSAGE_PREFIX L"vl::rpc_controller::RpcCalleeObjectEventOpsForList::RpcCalleeObjectEventOpsForList(...)#"
			CHECK_ERROR(listEventOps && objectEventOps, ERROR_MESSAGE_PREFIX L"List event ops and object event ops are required.");
#undef ERROR_MESSAGE_PREFIX
		}

		Value RpcCalleeObjectEventOpsForList::InvokeEvent(RpcObjectReference ref, vint eventId, Ptr<IValueArray> arguments)
		{
			if (eventId == RpcEventId_IValueObservableList_ItemChanged)
			{
				return listEventOps->OnItemChanged(
					ref,
					UnboxValue<vint>(DeserializeValue(serializer, arguments->Get(0))),
					UnboxValue<vint>(DeserializeValue(serializer, arguments->Get(1))),
					UnboxValue<vint>(DeserializeValue(serializer, arguments->Get(2)))
					);
			}
			return objectEventOps->InvokeEvent(ref, eventId, arguments);
		}

/***********************************************************************
* RpcCallerListOps
***********************************************************************/

		RpcCallerListOps::RpcCallerListOps(IRpcObjectOps* _objectOps, IRpcSerializer* _serializer)
			: objectOps(_objectOps)
			, serializer(_serializer)
		{
#define ERROR_MESSAGE_PREFIX L"vl::rpc_controller::RpcCallerListOps::RpcCallerListOps(...)#"
			CHECK_ERROR(objectOps, ERROR_MESSAGE_PREFIX L"Object ops are required.");
#undef ERROR_MESSAGE_PREFIX
		}

		RpcObjectReference RpcCallerListOps::EnumCreate(RpcObjectReference ref)
		{
			auto result = InvokeListMethod(objectOps, serializer, ref, RpcMethodId_IValueEnumerable_CreateEnumerator, CreateRpcArguments());
			return UnboxValue<RpcObjectReference>(result);
		}

		bool RpcCallerListOps::EnumNext(RpcObjectReference enumerator)
		{
			auto result = InvokeListMethod(objectOps, serializer, enumerator, RpcMethodId_IValueEnumerator_Next, CreateRpcArguments());
			return UnboxValue<bool>(result);
		}

		Value RpcCallerListOps::EnumGetCurrent(RpcObjectReference enumerator)
		{
			return InvokeListMethod(objectOps, serializer, enumerator, RpcMethodId_IValueEnumerator_GetCurrent, CreateRpcArguments());
		}

		vint RpcCallerListOps::ListGetCount(RpcObjectReference ref)
		{
			auto result = InvokeListMethod(objectOps, serializer, ref, RpcMethodId_IValueReadonlyList_GetCount, CreateRpcArguments());
			return UnboxValue<vint>(result);
		}

		Value RpcCallerListOps::ListGet(RpcObjectReference ref, vint index)
		{
			return InvokeListMethod(objectOps, serializer, ref, RpcMethodId_IValueReadonlyList_Get, CreateRpcArguments(SerializeValue(serializer, BoxValue(index))));
		}

		void RpcCallerListOps::ListSet(RpcObjectReference ref, vint index, const Value& value)
		{
			InvokeListMethod(objectOps, serializer, ref, RpcMethodId_IValueList_Set, CreateRpcArguments(SerializeValue(serializer, BoxValue(index)), value));
		}

		vint RpcCallerListOps::ListAdd(RpcObjectReference ref, const Value& value)
		{
			auto result = InvokeListMethod(objectOps, serializer, ref, RpcMethodId_IValueList_Add, CreateRpcArguments(value));
			return UnboxValue<vint>(result);
		}

		vint RpcCallerListOps::ListInsert(RpcObjectReference ref, vint index, const Value& value)
		{
			auto result = InvokeListMethod(objectOps, serializer, ref, RpcMethodId_IValueList_Insert, CreateRpcArguments(SerializeValue(serializer, BoxValue(index)), value));
			return UnboxValue<vint>(result);
		}

		bool RpcCallerListOps::ListRemoveAt(RpcObjectReference ref, vint index)
		{
			auto result = InvokeListMethod(objectOps, serializer, ref, RpcMethodId_IValueList_RemoveAt, CreateRpcArguments(SerializeValue(serializer, BoxValue(index))));
			return UnboxValue<bool>(result);
		}

		void RpcCallerListOps::ListClear(RpcObjectReference ref)
		{
			InvokeListMethod(objectOps, serializer, ref, RpcMethodId_IValueList_Clear, CreateRpcArguments());
		}

		bool RpcCallerListOps::ListContains(RpcObjectReference ref, const Value& value)
		{
			auto result = InvokeListMethod(objectOps, serializer, ref, RpcMethodId_IValueReadonlyList_Contains, CreateRpcArguments(value));
			return UnboxValue<bool>(result);
		}

		vint RpcCallerListOps::ListIndexOf(RpcObjectReference ref, const Value& value)
		{
			auto result = InvokeListMethod(objectOps, serializer, ref, RpcMethodId_IValueReadonlyList_IndexOf, CreateRpcArguments(value));
			return UnboxValue<vint>(result);
		}

		void RpcCallerListOps::ArrayResize(RpcObjectReference ref, vint size)
		{
			InvokeListMethod(objectOps, serializer, ref, RpcMethodId_IValueArray_Resize, CreateRpcArguments(SerializeValue(serializer, BoxValue(size))));
		}

		vint RpcCallerListOps::DictGetCount(RpcObjectReference ref)
		{
			auto result = InvokeListMethod(objectOps, serializer, ref, RpcMethodId_IValueReadonlyDictionary_GetCount, CreateRpcArguments());
			return UnboxValue<vint>(result);
		}

		Value RpcCallerListOps::DictGet(RpcObjectReference ref, const Value& key)
		{
			return InvokeListMethod(objectOps, serializer, ref, RpcMethodId_IValueReadonlyDictionary_Get, CreateRpcArguments(key));
		}

		void RpcCallerListOps::DictSet(RpcObjectReference ref, const Value& key, const Value& value)
		{
			InvokeListMethod(objectOps, serializer, ref, RpcMethodId_IValueDictionary_Set, CreateRpcArguments(key, value));
		}

		bool RpcCallerListOps::DictRemove(RpcObjectReference ref, const Value& key)
		{
			auto result = InvokeListMethod(objectOps, serializer, ref, RpcMethodId_IValueDictionary_Remove, CreateRpcArguments(key));
			return UnboxValue<bool>(result);
		}

		void RpcCallerListOps::DictClear(RpcObjectReference ref)
		{
			InvokeListMethod(objectOps, serializer, ref, RpcMethodId_IValueDictionary_Clear, CreateRpcArguments());
		}

		bool RpcCallerListOps::DictContainsKey(RpcObjectReference ref, const Value& key)
		{
			auto result = InvokeListMethod(objectOps, serializer, ref, RpcMethodId_IValueReadonlyDictionary_ContainsKey, CreateRpcArguments(key));
			return UnboxValue<bool>(result);
		}

		RpcObjectReference RpcCallerListOps::DictGetKeys(RpcObjectReference ref)
		{
			auto result = InvokeListMethod(objectOps, serializer, ref, RpcMethodId_IValueReadonlyDictionary_GetKeys, CreateRpcArguments());
			return UnboxValue<RpcObjectReference>(result);
		}

		RpcObjectReference RpcCallerListOps::DictGetValues(RpcObjectReference ref)
		{
			auto result = InvokeListMethod(objectOps, serializer, ref, RpcMethodId_IValueReadonlyDictionary_GetValues, CreateRpcArguments());
			return UnboxValue<RpcObjectReference>(result);
		}

/***********************************************************************
* RpcCallerListEventOps
***********************************************************************/

		RpcCallerListEventOps::RpcCallerListEventOps(IRpcObjectEventOps* _objectEventOps, IRpcSerializer* _serializer)
			: objectEventOps(_objectEventOps)
			, serializer(_serializer)
		{
#define ERROR_MESSAGE_PREFIX L"vl::rpc_controller::RpcCallerListEventOps::RpcCallerListEventOps(...)#"
			CHECK_ERROR(objectEventOps, ERROR_MESSAGE_PREFIX L"Object event ops are required.");
#undef ERROR_MESSAGE_PREFIX
		}

		Value RpcCallerListEventOps::OnItemChanged(RpcObjectReference ref, vint index, vint oldCount, vint newCount)
		{
			auto arguments = CreateRpcArguments(
				SerializeValue(serializer, BoxValue(index)),
				SerializeValue(serializer, BoxValue(oldCount)),
				SerializeValue(serializer, BoxValue(newCount))
				);
			auto result = objectEventOps->InvokeEvent(ref, RpcEventId_IValueObservableList_ItemChanged, arguments);
			ReadEventException(UnboxValue<RpcEventExceptionMap>(DeserializeValue(serializer, result)));
			return result;
		}
	}
}


/***********************************************************************
.\RPCJSON\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);
			}

			Ptr<JsonObject> GetJsonObject(Ptr<JsonNode> node)
			{
				auto object = node.Cast<JsonObject>();
				CHECK_ERROR(object, L"JSON object is expected.");
				return object;
			}

			Ptr<JsonArray> GetJsonArray(Ptr<JsonNode> node)
			{
				auto array = node.Cast<JsonArray>();
				CHECK_ERROR(array, L"JSON array is expected.");
				return array;
			}

			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);
			}

			void SetJsonObjectField(Ptr<JsonObject> object, const WString& name, Ptr<JsonNode> value)
			{
				for (auto field : object->fields)
				{
					if (field->name.value == name)
					{
						field->value = value;
						return;
					}
				}
				AddJsonObjectField(object, name, value);
			}

			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;
			}

			vint GetJsonInt(Ptr<JsonNode> node)
			{
				return __vwsn::Parse<vint>(GetJsonNumber(node));
			}

			bool GetJsonBool(Ptr<JsonNode> node)
			{
				auto literal = node.Cast<JsonLiteral>();
				CHECK_ERROR(literal, L"JSON boolean is expected.");
				if (literal->value == JsonLiteralValue::True) return true;
				if (literal->value == JsonLiteralValue::False) return false;
				CHECK_FAIL(L"JSON boolean is expected.");
				return false;
			}

			Ptr<JsonNumber> CreateJsonNumber(vint value)
			{
				return CreateJsonNumber(__vwsn::ToString(value));
			}

			Ptr<JsonLiteral> CreateJsonBool(bool value)
			{
				return CreateJsonLiteral(value ? JsonLiteralValue::True : JsonLiteralValue::False);
			}

			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 BoxValue(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 BoxValue(RpcException{
						GetJsonString(GetJsonObjectField(object, WString::Unmanaged(L"message"))),
						});
				}
				return {};
			}

			RpcObjectReference GetRpcObjectReferenceFromJson(Ptr<JsonNode> node)
			{
				auto object = GetJsonObject(node);
				return {
					GetJsonInt(GetJsonObjectField(object, WString::Unmanaged(L"clientId"))),
					GetJsonInt(GetJsonObjectField(object, WString::Unmanaged(L"objectId"))),
					GetJsonInt(GetJsonObjectField(object, WString::Unmanaged(L"typeId"))),
					};
			}

			Ptr<JsonObject> CreateRpcObjectReferenceJson(RpcObjectReference ref)
			{
				auto object = CreateJsonObject();
				AddJsonObjectField(object, WString::Unmanaged(L"clientId"), CreateJsonNumber(ref.clientId));
				AddJsonObjectField(object, WString::Unmanaged(L"objectId"), CreateJsonNumber(ref.objectId));
				AddJsonObjectField(object, WString::Unmanaged(L"typeId"), CreateJsonNumber(ref.typeId));
				return object;
			}

			Ptr<JsonNode> ValueToJsonNode(const Value& value)
			{
				if (value.GetValueType() == Value::SharedPtr)
				{
					if (auto node = value.GetSharedPtr().Cast<JsonNode>())
					{
						return node;
					}
				}
				CHECK_FAIL(L"RPC JSON value should be a Ptr<JsonNode>.");
				return nullptr;
			}

			Ptr<JsonArray> ValueArrayToJsonArray(Ptr<IValueArray> arguments)
			{
				auto array = CreateJsonArray();
				for (vint i = 0; i < arguments->GetCount(); i++)
				{
					array->items.Add(ValueToJsonNode(arguments->Get(i)));
				}
				return array;
			}

			Ptr<IValueArray> JsonArrayToValueArray(Ptr<JsonNode> node)
			{
				auto array = GetJsonArray(node);
				auto arguments = IValueArray::Create();
				arguments->Resize(array->items.Count());
				for (vint i = 0; i < array->items.Count(); i++)
				{
					arguments->Set(i, BoxValue(array->items[i]));
				}
				return arguments;
			}

			Ptr<JsonObject> CreateRpcMessage(const WString& method, vint requestId, vint sourceClientId)
			{
				auto object = CreateJsonObject();
				AddJsonObjectField(object, WString::Unmanaged(L"rpcMethod"), CreateJsonString(method));
				AddJsonObjectField(object, WString::Unmanaged(L"rpcRequestId"), CreateJsonNumber(requestId));
				AddJsonObjectField(object, WString::Unmanaged(L"sourceClientId"), CreateJsonNumber(sourceClientId));
				return object;
			}

			vint ReadSourceClientId(Ptr<JsonObject> object)
			{
				return GetJsonInt(GetJsonObjectField(object, WString::Unmanaged(L"sourceClientId")));
			}

			vint ReadTargetClientId(Ptr<JsonObject> object)
			{
				return GetJsonInt(GetJsonObjectField(object, WString::Unmanaged(L"targetClientId")));
			}

			bool IsRpcMethodPrefix(const WString& rpcMethod, const WString& prefix)
			{
				return rpcMethod.Length() >= prefix.Length() && rpcMethod.Left(prefix.Length()) == prefix;
			}

			Ptr<JsonNode> MethodResultToJsonResponse(const Value& result)
			{
				if (result.GetValueType() == Value::SharedPtr)
				{
					if (auto byvalReturnValue = result.GetSharedPtr().Cast<RpcByvalReturnValue>())
					{
						auto object = CreateJsonObject();
						AddJsonObjectField(object, WString::Unmanaged(L"value"), ValueToJsonNode(byvalReturnValue->value));
						AddJsonObjectField(object, WString::Unmanaged(L"slot"), CreateJsonNumber(byvalReturnValue->slot));
						return object;
					}
				}
				return ValueToJsonNode(result);
			}

			Value JsonResponseToMethodResult(Ptr<JsonNode> node)
			{
				if (auto object = node.Cast<JsonObject>())
				{
					auto valueNode = FindJsonObjectField(object, WString::Unmanaged(L"value"));
					auto slotNode = FindJsonObjectField(object, WString::Unmanaged(L"slot"));
					if (valueNode && slotNode)
					{
						auto byvalReturnValue = Ptr(new RpcByvalReturnValue);
						byvalReturnValue->value = BoxValue(valueNode);
						byvalReturnValue->slot = GetJsonInt(slotNode);
						return BoxValue(byvalReturnValue);
					}
				}
				return BoxValue(node);
			}

			Ptr<JsonNode> SerializePredefinedValue(const Value& value)
			{
				RpcJsonSerializeCallback rpcjson_Serialize;
				rpcjson_Serialize = Func<Ptr<JsonNode>(const Value&)>([&rpcjson_Serialize](const Value& item)
				{
					return JsonSerializePredefinedTypes(item, rpcjson_Serialize);
				});
				return JsonSerializePredefinedTypes(value, rpcjson_Serialize);
			}

			Value DeserializePredefinedValue(Ptr<JsonNode> node)
			{
				RpcJsonDeserializeCallback rpcjson_Deserialize;
				rpcjson_Deserialize = Func<Value(Ptr<JsonNode>)>([&rpcjson_Deserialize](Ptr<JsonNode> item)
				{
					return JsonDeserializePredefinedTypes(BoxValue(item), rpcjson_Deserialize);
				});
				return JsonDeserializePredefinedTypes(BoxValue(node), rpcjson_Deserialize);
			}

			Ptr<JsonObject> CreatePlainRpcException(const RpcException& exception)
			{
				auto result = CreateJsonObject();
				AddJsonObjectField(result, WString::Unmanaged(L"message"), CreateJsonString(exception.message));
				return result;
			}

			RpcException ReadPlainRpcException(Ptr<JsonNode> node)
			{
				auto object = GetJsonObject(node);
				return { GetJsonString(GetJsonObjectField(object, WString::Unmanaged(L"message"))) };
			}

			Ptr<JsonNode> CreateEventExceptionResponse(Ptr<JsonNode> serialized)
			{
				auto value = DeserializePredefinedValue(serialized);
				if (value.IsNull())
				{
					return CreateJsonLiteral(JsonLiteralValue::Null);
				}

				auto exceptions = UnboxValue<RpcEventExceptionMap>(value);
				auto result = CreateJsonArray();
				auto keys = exceptions->GetKeys();
				for (vint i = 0; i < keys->GetCount(); i++)
				{
					auto key = keys->Get(i);
					auto resultPair = CreateJsonArray();
					resultPair->items.Add(CreateJsonNumber(UnboxValue<vint>(key)));
					resultPair->items.Add(CreatePlainRpcException(UnboxValue<RpcException>(exceptions->Get(key))));
					result->items.Add(resultPair);
				}
				return result;
			}

			Ptr<JsonNode> CreateSerializedEventExceptionMap(Ptr<JsonNode> response)
			{
				if (auto literal = response.Cast<JsonLiteral>())
				{
					CHECK_ERROR(literal->value == JsonLiteralValue::Null, L"RPC event exception response should be null or an array.");
					return SerializePredefinedValue({});
				}

				auto array = GetJsonArray(response);
				auto exceptions = IValueDictionary::Create();
				for (auto item : array->items)
				{
					auto pair = GetJsonArray(item);
					CHECK_ERROR(pair->items.Count() == 2, L"RPC event exception response pair is expected.");
					exceptions->Set(BoxValue(GetJsonInt(pair->items[0])), BoxValue(ReadPlainRpcException(pair->items[1])));
				}
				return SerializePredefinedValue(BoxValue(exceptions));
			}
		}

		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.");
		}

/***********************************************************************
* IRpcJsonMessageDispatcher
***********************************************************************/

		Ptr<JsonNode> IRpcJsonMessageDispatcher::DefaultTranslate(
			Ptr<JsonNode> message,
			RequestType requestType,
			IRpcObjectOps* objectOps,
			IRpcObjectEventOps* objectEventOps,
			IRpcDispatcher* dispatcher,
			IRpcLifecycle* lifecycle
			)
		{
#define ERROR_MESSAGE_PREFIX L"vl::rpc_controller::IRpcJsonMessageDispatcher::DefaultTranslate(Ptr<JsonNode>, RequestType, IRpcObjectOps*, IRpcObjectEventOps*, IRpcDispatcher*, IRpcLifecycle*)#"
			auto request = GetJsonObject(message);
			auto rpcMethod = GetJsonString(GetJsonObjectField(request, WString::Unmanaged(L"rpcMethod")));

			if (requestType == RequestType::Direct && IsRpcMethodPrefix(rpcMethod, WString::Unmanaged(L"Request:IObjectOps_")))
			{
				return RpcJsonObjectOps::Translate(message, objectOps, lifecycle);
			}
			else if (requestType == RequestType::Broadcast && IsRpcMethodPrefix(rpcMethod, WString::Unmanaged(L"Request:IObjectEventOps_")))
			{
				return RpcJsonObjectEventOps::Translate(message, objectEventOps, lifecycle);
			}
			else if (requestType == RequestType::BroadcastAndDrop && rpcMethod == WString::Unmanaged(L"Request:IRpcDispatcher_DeclareRemoteService"))
			{
				RpcJsonDispatcher::Translate(message, dispatcher, lifecycle);
				return nullptr;
			}

			CHECK_FAIL(ERROR_MESSAGE_PREFIX L"Unknown JSON RPC method.");
			return nullptr;
#undef ERROR_MESSAGE_PREFIX
		}

/***********************************************************************
* RpcJsonObjectOps
***********************************************************************/

		RpcJsonObjectOps::RpcJsonObjectOps(IRpcJsonMessageDispatcher* _dispatcher)
			: dispatcher(_dispatcher)
		{
#define ERROR_MESSAGE_PREFIX L"vl::rpc_controller::RpcJsonObjectOps::RpcJsonObjectOps(...)#"
			CHECK_ERROR(dispatcher, ERROR_MESSAGE_PREFIX L"Dispatcher is required.");
#undef ERROR_MESSAGE_PREFIX
		}

		RpcJsonObjectOps::RpcJsonObjectOps(vint _sourceClientId, vint _targetClientId, IRpcJsonMessageDispatcher* _dispatcher)
			: sourceClientId(_sourceClientId)
			, targetClientId(_targetClientId)
			, dispatcher(_dispatcher)
		{
#define ERROR_MESSAGE_PREFIX L"vl::rpc_controller::RpcJsonObjectOps::RpcJsonObjectOps(...)#"
			CHECK_ERROR(dispatcher, ERROR_MESSAGE_PREFIX L"Dispatcher is required.");
#undef ERROR_MESSAGE_PREFIX
		}

		RpcJsonObjectOps::~RpcJsonObjectOps()
		{
		}

		Value RpcJsonObjectOps::InvokeMethod(RpcObjectReference ref, vint methodId, Ptr<IValueArray> arguments)
		{
#define ERROR_MESSAGE_PREFIX L"vl::rpc_controller::RpcJsonObjectOps::InvokeMethod(RpcObjectReference, vint, Ptr<IValueArray>)#"
			CHECK_ERROR(dispatcher, ERROR_MESSAGE_PREFIX L"Dispatcher is required.");
			auto request = CreateRpcMessage(WString::Unmanaged(L"Request:IObjectOps_InvokeMethod"), dispatcher->AllocateRequestId(), sourceClientId);
			AddJsonObjectField(request, WString::Unmanaged(L"targetClientId"), CreateJsonNumber(targetClientId == RpcClientId_Invalid ? ref.clientId : targetClientId));
			AddJsonObjectField(request, WString::Unmanaged(L"ref"), CreateRpcObjectReferenceJson(ref));
			AddJsonObjectField(request, WString::Unmanaged(L"methodId"), CreateJsonNumber(methodId));
			AddJsonObjectField(request, WString::Unmanaged(L"arguments"), ValueArrayToJsonArray(arguments));

			auto response = GetJsonObject(dispatcher->OnJsonRequest(request, IRpcJsonMessageDispatcher::RequestType::Direct));
			CHECK_ERROR(GetJsonString(GetJsonObjectField(response, WString::Unmanaged(L"rpcMethod"))) == WString::Unmanaged(L"Response:IObjectOps_InvokeMethod"), ERROR_MESSAGE_PREFIX L"Unexpected response method.");
			CHECK_ERROR(ReadRequestId(response) == ReadRequestId(request), ERROR_MESSAGE_PREFIX L"Unexpected response request id.");
			return JsonResponseToMethodResult(GetJsonObjectField(response, WString::Unmanaged(L"response")));
#undef ERROR_MESSAGE_PREFIX
		}

		void RpcJsonObjectOps::EndInvokeMethod(vint slot)
		{
#define ERROR_MESSAGE_PREFIX L"vl::rpc_controller::RpcJsonObjectOps::EndInvokeMethod(vint)#"
			CHECK_ERROR(dispatcher, ERROR_MESSAGE_PREFIX L"Dispatcher is required.");
			auto request = CreateRpcMessage(WString::Unmanaged(L"Request:IObjectOps_EndInvokeMethod"), dispatcher->AllocateRequestId(), sourceClientId);
			AddJsonObjectField(request, WString::Unmanaged(L"targetClientId"), CreateJsonNumber(targetClientId));
			AddJsonObjectField(request, WString::Unmanaged(L"slot"), CreateJsonNumber(slot));

			auto response = GetJsonObject(dispatcher->OnJsonRequest(request, IRpcJsonMessageDispatcher::RequestType::Direct));
			CHECK_ERROR(GetJsonString(GetJsonObjectField(response, WString::Unmanaged(L"rpcMethod"))) == WString::Unmanaged(L"Response:IObjectOps_EndInvokeMethod"), ERROR_MESSAGE_PREFIX L"Unexpected response method.");
			CHECK_ERROR(ReadRequestId(response) == ReadRequestId(request), ERROR_MESSAGE_PREFIX L"Unexpected response request id.");
#undef ERROR_MESSAGE_PREFIX
		}

		void RpcJsonObjectOps::ObjectHold(RpcObjectReference ref, vint remoteClientId, bool hold)
		{
#define ERROR_MESSAGE_PREFIX L"vl::rpc_controller::RpcJsonObjectOps::ObjectHold(RpcObjectReference, vint, bool)#"
			CHECK_ERROR(dispatcher, ERROR_MESSAGE_PREFIX L"Dispatcher is required.");
			auto request = CreateRpcMessage(WString::Unmanaged(L"Request:IObjectOps_ObjectHold"), dispatcher->AllocateRequestId(), sourceClientId == RpcClientId_Invalid ? remoteClientId : sourceClientId);
			AddJsonObjectField(request, WString::Unmanaged(L"targetClientId"), CreateJsonNumber(targetClientId == RpcClientId_Invalid ? ref.clientId : targetClientId));
			AddJsonObjectField(request, WString::Unmanaged(L"ref"), CreateRpcObjectReferenceJson(ref));
			AddJsonObjectField(request, WString::Unmanaged(L"remoteClientId"), CreateJsonNumber(remoteClientId));
			AddJsonObjectField(request, WString::Unmanaged(L"hold"), CreateJsonBool(hold));

			auto response = GetJsonObject(dispatcher->OnJsonRequest(request, IRpcJsonMessageDispatcher::RequestType::Direct));
			CHECK_ERROR(GetJsonString(GetJsonObjectField(response, WString::Unmanaged(L"rpcMethod"))) == WString::Unmanaged(L"Response:IObjectOps_ObjectHold"), ERROR_MESSAGE_PREFIX L"Unexpected response method.");
			CHECK_ERROR(ReadRequestId(response) == ReadRequestId(request), ERROR_MESSAGE_PREFIX L"Unexpected response request id.");
#undef ERROR_MESSAGE_PREFIX
		}

		Ptr<JsonNode> RpcJsonObjectOps::Translate(Ptr<JsonNode> message, IRpcObjectOps* ops, IRpcLifecycle* lifecycle)
		{
#define ERROR_MESSAGE_PREFIX L"vl::rpc_controller::RpcJsonObjectOps::Translate(Ptr<JsonNode>, IRpcObjectOps*)#"
			(void)lifecycle;
			CHECK_ERROR(ops, ERROR_MESSAGE_PREFIX L"Object ops is required.");
			auto request = GetJsonObject(message);
			auto rpcMethod = GetJsonString(GetJsonObjectField(request, WString::Unmanaged(L"rpcMethod")));
			auto requestId = ReadRequestId(request);
			auto sourceClientId = ReadSourceClientId(request);
			auto targetClientId = ReadTargetClientId(request);
			auto responseMethod =
				rpcMethod == WString::Unmanaged(L"Request:IObjectOps_InvokeMethod") ? WString::Unmanaged(L"Response:IObjectOps_InvokeMethod") :
				rpcMethod == WString::Unmanaged(L"Request:IObjectOps_EndInvokeMethod") ? WString::Unmanaged(L"Response:IObjectOps_EndInvokeMethod") :
				rpcMethod == WString::Unmanaged(L"Request:IObjectOps_ObjectHold") ? WString::Unmanaged(L"Response:IObjectOps_ObjectHold") :
				WString::Empty;
			CHECK_ERROR(responseMethod != WString::Empty, ERROR_MESSAGE_PREFIX L"Unexpected RPC method.");
			auto response = CreateRpcMessage(responseMethod, requestId, lifecycle ? lifecycle->GetClientId() : targetClientId);
			AddJsonObjectField(response, WString::Unmanaged(L"targetClientId"), CreateJsonNumber(sourceClientId));

			if (rpcMethod == WString::Unmanaged(L"Request:IObjectOps_InvokeMethod"))
			{
				auto result = ops->InvokeMethod(
					GetRpcObjectReferenceFromJson(GetJsonObjectField(request, WString::Unmanaged(L"ref"))),
					GetJsonInt(GetJsonObjectField(request, WString::Unmanaged(L"methodId"))),
					JsonArrayToValueArray(GetJsonObjectField(request, WString::Unmanaged(L"arguments")))
					);
				AddJsonObjectField(response, WString::Unmanaged(L"response"), MethodResultToJsonResponse(result));
			}
			else if (rpcMethod == WString::Unmanaged(L"Request:IObjectOps_EndInvokeMethod"))
			{
				ops->EndInvokeMethod(GetJsonInt(GetJsonObjectField(request, WString::Unmanaged(L"slot"))));
			}
			else if (rpcMethod == WString::Unmanaged(L"Request:IObjectOps_ObjectHold"))
			{
				ops->ObjectHold(
					GetRpcObjectReferenceFromJson(GetJsonObjectField(request, WString::Unmanaged(L"ref"))),
					GetJsonInt(GetJsonObjectField(request, WString::Unmanaged(L"remoteClientId"))),
					GetJsonBool(GetJsonObjectField(request, WString::Unmanaged(L"hold")))
					);
			}
			else
			{
				CHECK_FAIL(ERROR_MESSAGE_PREFIX L"Unexpected RPC method.");
			}
			return response;
#undef ERROR_MESSAGE_PREFIX
		}

/***********************************************************************
* RpcJsonObjectEventOps
***********************************************************************/

		RpcJsonObjectEventOps::RpcJsonObjectEventOps(IRpcJsonMessageDispatcher* _dispatcher)
			: dispatcher(_dispatcher)
		{
#define ERROR_MESSAGE_PREFIX L"vl::rpc_controller::RpcJsonObjectEventOps::RpcJsonObjectEventOps(...)#"
			CHECK_ERROR(dispatcher, ERROR_MESSAGE_PREFIX L"Dispatcher is required.");
#undef ERROR_MESSAGE_PREFIX
		}

		RpcJsonObjectEventOps::RpcJsonObjectEventOps(vint _sourceClientId, IRpcJsonMessageDispatcher* _dispatcher)
			: sourceClientId(_sourceClientId)
			, dispatcher(_dispatcher)
		{
#define ERROR_MESSAGE_PREFIX L"vl::rpc_controller::RpcJsonObjectEventOps::RpcJsonObjectEventOps(...)#"
			CHECK_ERROR(dispatcher, ERROR_MESSAGE_PREFIX L"Dispatcher is required.");
#undef ERROR_MESSAGE_PREFIX
		}

		RpcJsonObjectEventOps::~RpcJsonObjectEventOps()
		{
		}

		Value RpcJsonObjectEventOps::InvokeEvent(RpcObjectReference ref, vint eventId, Ptr<IValueArray> arguments)
		{
#define ERROR_MESSAGE_PREFIX L"vl::rpc_controller::RpcJsonObjectEventOps::InvokeEvent(RpcObjectReference, vint, Ptr<IValueArray>)#"
			CHECK_ERROR(dispatcher, ERROR_MESSAGE_PREFIX L"Dispatcher is required.");
			auto request = CreateRpcMessage(WString::Unmanaged(L"Request:IObjectEventOps_InvokeEvent"), dispatcher->AllocateRequestId(), sourceClientId);
			AddJsonObjectField(request, WString::Unmanaged(L"ref"), CreateRpcObjectReferenceJson(ref));
			AddJsonObjectField(request, WString::Unmanaged(L"eventId"), CreateJsonNumber(eventId));
			AddJsonObjectField(request, WString::Unmanaged(L"arguments"), ValueArrayToJsonArray(arguments));

			auto response = GetJsonObject(dispatcher->OnJsonRequest(request, IRpcJsonMessageDispatcher::RequestType::Broadcast));
			CHECK_ERROR(GetJsonString(GetJsonObjectField(response, WString::Unmanaged(L"rpcMethod"))) == WString::Unmanaged(L"Response:Broadcast_Response"), ERROR_MESSAGE_PREFIX L"Unexpected response method.");
			CHECK_ERROR(ReadRequestId(response) == ReadRequestId(request), ERROR_MESSAGE_PREFIX L"Unexpected response request id.");
			return BoxValue(CreateSerializedEventExceptionMap(GetJsonObjectField(response, WString::Unmanaged(L"response"))));
#undef ERROR_MESSAGE_PREFIX
		}

		Ptr<JsonNode> RpcJsonObjectEventOps::Translate(Ptr<JsonNode> message, IRpcObjectEventOps* ops, IRpcLifecycle* lifecycle)
		{
#define ERROR_MESSAGE_PREFIX L"vl::rpc_controller::RpcJsonObjectEventOps::Translate(Ptr<JsonNode>, IRpcObjectEventOps*)#"
			CHECK_ERROR(ops, ERROR_MESSAGE_PREFIX L"Object event ops is required.");
			auto request = GetJsonObject(message);
			auto rpcMethod = GetJsonString(GetJsonObjectField(request, WString::Unmanaged(L"rpcMethod")));
			CHECK_ERROR(rpcMethod == WString::Unmanaged(L"Request:IObjectEventOps_InvokeEvent"), ERROR_MESSAGE_PREFIX L"Unexpected RPC method.");
			auto requestId = ReadRequestId(request);
			auto sourceClientId = ReadSourceClientId(request);
			auto response = CreateRpcMessage(WString::Unmanaged(L"Response:Broadcast_Response"), requestId, lifecycle ? lifecycle->GetClientId() : RpcClientId_Invalid);
			AddJsonObjectField(response, WString::Unmanaged(L"targetClientId"), CreateJsonNumber(sourceClientId));

			auto result = ops->InvokeEvent(
				GetRpcObjectReferenceFromJson(GetJsonObjectField(request, WString::Unmanaged(L"ref"))),
				GetJsonInt(GetJsonObjectField(request, WString::Unmanaged(L"eventId"))),
				JsonArrayToValueArray(GetJsonObjectField(request, WString::Unmanaged(L"arguments")))
				);
			AddJsonObjectField(response, WString::Unmanaged(L"response"), CreateEventExceptionResponse(ValueToJsonNode(result)));
			return response;
#undef ERROR_MESSAGE_PREFIX
		}

/***********************************************************************
* RpcJsonDispatcher
***********************************************************************/

		RpcJsonDispatcher::RpcJsonDispatcher(vint _sourceClientId, IRpcJsonMessageDispatcher* _dispatcher)
			: sourceClientId(_sourceClientId)
			, dispatcher(_dispatcher)
		{
#define ERROR_MESSAGE_PREFIX L"vl::rpc_controller::RpcJsonDispatcher::RpcJsonDispatcher(vint, IRpcJsonMessageDispatcher*)#"
			CHECK_ERROR(sourceClientId != RpcClientId_Invalid, ERROR_MESSAGE_PREFIX L"Source client id is required.");
			CHECK_ERROR(dispatcher, ERROR_MESSAGE_PREFIX L"Dispatcher is required.");
#undef ERROR_MESSAGE_PREFIX
		}

		void RpcJsonDispatcher::Finalize()
		{
		}

		void RpcJsonDispatcher::Initialize()
		{
		}

		void RpcJsonDispatcher::DeclareLocalService(RpcObjectReference ref)
		{
#define ERROR_MESSAGE_PREFIX L"vl::rpc_controller::RpcJsonDispatcher::DeclareLocalService(RpcObjectReference)#"
			CHECK_ERROR(dispatcher, ERROR_MESSAGE_PREFIX L"Dispatcher is required.");
			CHECK_ERROR(ref.clientId == sourceClientId, ERROR_MESSAGE_PREFIX L"Client id does not match this dispatcher.");
			auto request = CreateRpcMessage(WString::Unmanaged(L"Request:IRpcDispatcher_DeclareRemoteService"), dispatcher->AllocateRequestId(), sourceClientId);
			AddJsonObjectField(request, WString::Unmanaged(L"ref"), CreateRpcObjectReferenceJson(ref));

			auto response = dispatcher->OnJsonRequest(request, IRpcJsonMessageDispatcher::RequestType::BroadcastAndDrop);
			CHECK_ERROR(!response, ERROR_MESSAGE_PREFIX L"DeclareLocalService should not receive a response.");
#undef ERROR_MESSAGE_PREFIX
		}

		IRpcObjectEventOps* RpcJsonDispatcher::BroadcastFromClient_ObjectEventOps(vint selfClientId)
		{
#define ERROR_MESSAGE_PREFIX L"vl::rpc_controller::RpcJsonDispatcher::BroadcastFromClient_ObjectEventOps(vint)#"
			CHECK_ERROR(selfClientId == sourceClientId, ERROR_MESSAGE_PREFIX L"Client id does not match this dispatcher.");
			if (!objectEventOps)
			{
				objectEventOps = Ptr(new RpcJsonObjectEventOps(sourceClientId, dispatcher));
			}
			return objectEventOps.Obj();
#undef ERROR_MESSAGE_PREFIX
		}

		IRpcObjectOps* RpcJsonDispatcher::SendToClient_ObjectOps(vint targetClientId)
		{
			if (auto index = objectOps.Keys().IndexOf(targetClientId); index != -1)
			{
				return objectOps.Values()[index].Obj();
			}

			auto ops = Ptr(new RpcJsonObjectOps(sourceClientId, targetClientId, dispatcher));
			objectOps.Set(targetClientId, ops);
			return ops.Obj();
		}

		Ptr<JsonNode> RpcJsonDispatcher::Translate(Ptr<JsonNode> message, IRpcDispatcher* dispatcher, IRpcLifecycle* lifecycle)
		{
#define ERROR_MESSAGE_PREFIX L"vl::rpc_controller::RpcJsonDispatcher::Translate(Ptr<JsonNode>, IRpcDispatcher*, IRpcLifecycle*)#"
			(void)dispatcher;
			CHECK_ERROR(lifecycle, ERROR_MESSAGE_PREFIX L"Lifecycle is required.");
			auto request = GetJsonObject(message);
			auto rpcMethod = GetJsonString(GetJsonObjectField(request, WString::Unmanaged(L"rpcMethod")));
			CHECK_ERROR(rpcMethod == WString::Unmanaged(L"Request:IRpcDispatcher_DeclareRemoteService"), ERROR_MESSAGE_PREFIX L"Unexpected RPC method.");
			auto sourceClientId = ReadSourceClientId(request);
			auto ref = GetRpcObjectReferenceFromJson(GetJsonObjectField(request, WString::Unmanaged(L"ref")));
			CHECK_ERROR(ref.clientId == sourceClientId, ERROR_MESSAGE_PREFIX L"Client id does not match the message source.");

			lifecycle->DeclareRemoteService(ref);
			return nullptr;
#undef ERROR_MESSAGE_PREFIX
		}

/***********************************************************************
* RpcJsonLifecycle
***********************************************************************/

		RpcJsonLifecycle::RpcJsonLifecycle(vint _clientId, RpcJsonDispatcher* _dispatcher)
			: RpcLifecycleBase(_clientId)
			, dispatcher(_dispatcher)
		{
#define ERROR_MESSAGE_PREFIX L"vl::rpc_controller::RpcJsonLifecycle::RpcJsonLifecycle(vint, RpcJsonDispatcher*)#"
			CHECK_ERROR(dispatcher, ERROR_MESSAGE_PREFIX L"Dispatcher is required.");
#undef ERROR_MESSAGE_PREFIX
		}

		void RpcJsonLifecycle::Register(
			Ptr<IRpcSerializer> _serializer,
			Ptr<IRpcObjectOps> _objectOps,
			Ptr<IRpcObjectEventOps> _objectEventOps,
			Func<vint(IDescriptable*)> _getTypeId,
			Func<void(RpcObjectReference, IDescriptable*)> _eventAttacher
			)
		{
			serializer = _serializer;
			getTypeId = _getTypeId;
			eventAttacher = _eventAttacher;
			listOps = Ptr(new RpcCalleeListOps(this, serializer.Obj()));
			listEventOps = Ptr(new RpcCalleeListEventOps(this, serializer.Obj()));
			objectOpsForList = Ptr(new RpcCalleeObjectOpsForList(listOps, _objectOps, serializer.Obj()));
			objectEventOpsForList = Ptr(new RpcCalleeObjectEventOpsForList(listEventOps, _objectEventOps, serializer.Obj()));
			GetController()->Register(objectOpsForList, objectEventOpsForList);
		}

		vint RpcJsonLifecycle::DecideTypeId(IDescriptable* obj)const
		{
			auto result = RpcLifecycleBase::DecideTypeId(obj);
			if (result != RpcTypeId_NotFound) return result;
			return getTypeId ? getTypeId(obj) : RpcTypeId_NotFound;
		}

		IRpcSerializer* RpcJsonLifecycle::GetSerializer()
		{
			return serializer.Obj();
		}

		IRpcDispatcher* RpcJsonLifecycle::GetDispatcher()
		{
			return dispatcher;
		}

		void RpcJsonLifecycle::AttachLocalObjectEvents(RpcObjectReference ref, IDescriptable* obj)
		{
			if (eventAttacher)
			{
				eventAttacher(ref, obj);
			}
		}

/***********************************************************************
* Request Id
***********************************************************************/

		vint ReadRequestId(Ptr<JsonNode> message)
		{
			return GetJsonInt(GetJsonObjectField(GetJsonObject(message), WString::Unmanaged(L"rpcRequestId")));
		}

		void WriteRequestId(Ptr<JsonNode> message, vint requestId)
		{
			SetJsonObjectField(GetJsonObject(message), WString::Unmanaged(L"rpcRequestId"), CreateJsonNumber(requestId));
		}
	}
}


/***********************************************************************
.\RPCJSON\WFLIBRARYRPCJSONDISPATCHERCLIENT.CPP
***********************************************************************/

#include <cwchar>

namespace vl::rpc_controller::channeling
{
	using namespace vl;
	using namespace vl::collections;
	using namespace vl::glr::json;
	using namespace vl::inter_process;
	using namespace vl::reflection;
	using namespace vl::reflection::description;
	using namespace vl::rpc_controller;

	namespace
	{
		Ptr<JsonString> CreateJsonString(const WString& value)
		{
			auto node = Ptr(new JsonString);
			node->content.value = value;
			return node;
		}

		Ptr<JsonNumber> CreateJsonNumber(vint value)
		{
			auto node = Ptr(new JsonNumber);
			node->content.value = itow(value);
			return node;
		}

		Ptr<JsonObject> CreateJsonObject()
		{
			return Ptr(new JsonObject);
		}

		Ptr<JsonObject> GetJsonObject(Ptr<JsonNode> node)
		{
			auto object = node.Cast<JsonObject>();
			CHECK_ERROR(object, L"RpcJsonDispatcherClient expects a JSON object.");
			return object;
		}

		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);
		}

		void SetJsonObjectField(Ptr<JsonObject> object, const WString& name, Ptr<JsonNode> value)
		{
			for (auto field : object->fields)
			{
				if (field->name.value == name)
				{
					field->value = value;
					return;
				}
			}
			AddJsonObjectField(object, name, value);
		}

		Ptr<JsonNode> FindJsonObjectField(Ptr<JsonObject> object, const WString& name)
		{
			for (auto field : object->fields)
			{
				if (field->name.value == name)
				{
					return field->value;
				}
			}
			return nullptr;
		}

		Ptr<JsonNode> GetJsonObjectField(Ptr<JsonObject> object, const WString& name)
		{
			auto field = FindJsonObjectField(object, name);
			CHECK_ERROR(field, L"RpcJsonDispatcherClient expects a JSON object field.");
			return field;
		}

		WString GetJsonString(Ptr<JsonNode> node)
		{
			auto stringNode = node.Cast<JsonString>();
			CHECK_ERROR(stringNode, L"RpcJsonDispatcherClient expects a JSON string.");
			return stringNode->content.value;
		}

		vint GetJsonInt(Ptr<JsonNode> node)
		{
			auto numberNode = node.Cast<JsonNumber>();
			CHECK_ERROR(numberNode, L"RpcJsonDispatcherClient expects a JSON number.");
			return wtoi(numberNode->content.value);
		}

		bool StartsWith(const WString& value, const wchar_t* prefix)
		{
			auto prefixLength = (vint)wcslen(prefix);
			return value.Length() >= prefixLength && wcsncmp(value.Buffer(), prefix, prefixLength) == 0;
		}

		WString TryReadRpcMethod(Ptr<JsonNode> message)
		{
			if (auto object = message.Cast<JsonObject>())
			{
				if (auto field = FindJsonObjectField(object, WString::Unmanaged(L"rpcMethod")))
				{
					if (auto stringNode = field.Cast<JsonString>())
					{
						return stringNode->content.value;
					}
				}
			}
			return WString::Empty;
		}

		bool IsRpcRequest(const WString& rpcMethod)
		{
			return StartsWith(rpcMethod, L"Request:");
		}

		bool IsRpcResponse(const WString& rpcMethod)
		{
			return StartsWith(rpcMethod, L"Response:");
		}

		bool IsDeclareRemoteServiceRequest(const WString& rpcMethod)
		{
			return rpcMethod == WString::Unmanaged(L"Request:IRpcDispatcher_DeclareRemoteService");
		}

		IRpcJsonMessageDispatcher::RequestType GetRequestType(const WString& rpcMethod)
		{
			if (StartsWith(rpcMethod, L"Request:IObjectOps_"))
			{
				return IRpcJsonMessageDispatcher::RequestType::Direct;
			}
			if (StartsWith(rpcMethod, L"Request:IObjectEventOps_"))
			{
				return IRpcJsonMessageDispatcher::RequestType::Broadcast;
			}
			if (IsDeclareRemoteServiceRequest(rpcMethod))
			{
				return IRpcJsonMessageDispatcher::RequestType::BroadcastAndDrop;
			}
			CHECK_FAIL(L"RpcJsonDispatcherClient received an unknown request method.");
			return IRpcJsonMessageDispatcher::RequestType::Direct;
		}

		vint ReadRequestId(Ptr<JsonNode> message)
		{
			return GetJsonInt(GetJsonObjectField(GetJsonObject(message), WString::Unmanaged(L"rpcRequestId")));
		}

		vint ReadTargetClientId(Ptr<JsonNode> message)
		{
			return GetJsonInt(GetJsonObjectField(GetJsonObject(message), WString::Unmanaged(L"targetClientId")));
		}

		vint ReadDeclaredServiceTypeId(Ptr<JsonNode> message)
		{
			auto ref = GetJsonObject(GetJsonObjectField(GetJsonObject(message), WString::Unmanaged(L"ref")));
			return GetJsonInt(GetJsonObjectField(ref, WString::Unmanaged(L"typeId")));
		}

		Ptr<JsonObject> CreateLoginMessage(vint serverClientId)
		{
			auto message = CreateJsonObject();
			AddJsonObjectField(message, WString::Unmanaged(L"rpcChannelingSystem"), CreateJsonString(WString::Unmanaged(L"Login")));
			AddJsonObjectField(message, WString::Unmanaged(L"serverClientId"), CreateJsonNumber(serverClientId));
			return message;
		}

		Ptr<JsonObject> CreateLogoutMessage()
		{
			auto message = CreateJsonObject();
			AddJsonObjectField(message, WString::Unmanaged(L"rpcChannelingSystem"), CreateJsonString(WString::Unmanaged(L"Logout")));
			return message;
		}

		bool TryReadLoginMessage(Ptr<JsonNode> message, vint& serverClientId)
		{
			if (auto object = message.Cast<JsonObject>())
			{
				auto systemField = FindJsonObjectField(object, WString::Unmanaged(L"rpcChannelingSystem"));
				if (systemField && GetJsonString(systemField) == WString::Unmanaged(L"Login"))
				{
					serverClientId = GetJsonInt(GetJsonObjectField(object, WString::Unmanaged(L"serverClientId")));
					return true;
				}
			}
			return false;
		}
	}

/***********************************************************************
RpcJsonDispatcherClient
***********************************************************************/

	RpcJsonDispatcherClient::RpcJsonDispatcherClient()
	{
		CHECK_ERROR(semaphoreMessages.Create(0, 65536), L"RpcJsonDispatcherClient failed to create the message semaphore.");
		CHECK_ERROR(eventServerLocalClientId.CreateManualUnsignal(false), L"RpcJsonDispatcherClient failed to create the server-client-id event.");
	}

	void RpcJsonDispatcherClient::PrepareConnection(JsonChannel* channel, const List<WString>& _waitingForServices)
	{
		CHECK_ERROR(channel, L"RpcJsonDispatcherClient needs an RPC channel.");
		CHECK_ERROR(!rpcChannel, L"RpcJsonDispatcherClient connection can only be initialized once.");
		rpcChannel = channel;
		CopyFrom(waitingForServices, _waitingForServices);
		if (waitingForServices.Count() > 0)
		{
			eventWaitingForServicesCreated = true;
			CHECK_ERROR(eventWaitingForServices.CreateManualUnsignal(false), L"RpcJsonDispatcherClient failed to create the service-waiting event.");
		}
		rpcChannel->Initialize(this);
	}

	void RpcJsonDispatcherClient::SetRpcObjects(Ptr<RpcJsonDispatcher> _rpcDispatcher, Ptr<RpcJsonLifecycle> _lifecycle)
	{
		CHECK_ERROR(_rpcDispatcher, L"RpcJsonDispatcherClient needs a dispatcher.");
		CHECK_ERROR(_lifecycle, L"RpcJsonDispatcherClient needs a lifecycle.");
		CHECK_ERROR(!rpcDispatcher, L"RpcJsonDispatcherClient RPC objects can only be initialized once.");
		rpcDispatcher = _rpcDispatcher;
		lifecycle = _lifecycle;
	}

	RpcJsonLifecycle* RpcJsonDispatcherClient::GetRpcJsonLifecycle()
	{
		CHECK_ERROR(lifecycle, L"RpcJsonDispatcherClient needs a lifecycle.");
		return lifecycle.Obj();
	}

	void RpcJsonDispatcherClient::ProcessCachedIncomingServiceDeclarations()
	{
		List<JsonPackage> cached;
		SPIN_LOCK(lockServiceDeclarations)
		{
			for (auto request : cachedIncomingServiceDeclarations)
			{
				cached.Add(request);
			}
			cachedIncomingServiceDeclarations.Clear();
		}

		for (auto request : cached)
		{
			ProcessIncomingServiceDeclaration(request);
		}
	}

	void RpcJsonDispatcherClient::SendCachedOutgoingServiceDeclarations()
	{
		List<JsonPackage> cached;
		SPIN_LOCK(lockServiceDeclarations)
		{
			for (auto request : cachedOutgoingServiceDeclarations)
			{
				cached.Add(request);
			}
			cachedOutgoingServiceDeclarations.Clear();
		}

		for (auto request : cached)
		{
			SendJsonRequest(request, RequestType::BroadcastAndDrop);
		}
	}

	void RpcJsonDispatcherClient::ProcessIncomingServiceDeclaration(JsonPackage request)
	{
		IRpcJsonMessageDispatcher::DefaultTranslate(
			request,
			RequestType::BroadcastAndDrop,
			lifecycle->GetController()->GetObjectOps(),
			lifecycle->GetController()->GetObjectEventOps(),
			lifecycle->GetDispatcher(),
			lifecycle.Obj()
			);
		UpdateWaitingForServices(request);
	}

	void RpcJsonDispatcherClient::UpdateWaitingForServices(JsonPackage request)
	{
		auto typeId = ReadDeclaredServiceTypeId(request);
		bool shouldSignal = false;
		SPIN_LOCK(lockWaitingForServices)
		{
			for (vint i = waitingForServices.Count(); i > 0; i--)
			{
				auto index = i - 1;
				if (lifecycle->GetTypeIdFromName(waitingForServices[index]) == typeId)
				{
					waitingForServices.RemoveAt(index);
				}
			}
			shouldSignal = waitingForServices.Count() == 0;
		}
		if (shouldSignal && eventWaitingForServicesCreated)
		{
			eventWaitingForServices.Signal();
		}
	}

	void RpcJsonDispatcherClient::WaitForServerClientId()
	{
		if (serverLocalClientId.load() == -1)
		{
			eventServerLocalClientId.Wait();
		}
	}

	void RpcJsonDispatcherClient::WaitForExpectedServices()
	{
		if (eventWaitingForServicesCreated)
		{
			eventWaitingForServices.Wait();
		}
	}

	void RpcJsonDispatcherClient::SendJsonRequest(JsonPackage message, RequestType requestType)
	{
		CHECK_ERROR(rpcChannel, L"RpcJsonDispatcherClient needs an RPC channel.");
		switch (requestType)
		{
		case RequestType::Direct:
			rpcChannel->SendToClient(ReadTargetClientId(message), message);
			break;
		case RequestType::Broadcast:
		case RequestType::BroadcastAndDrop:
			WaitForServerClientId();
			rpcChannel->SendToClient(serverLocalClientId.load(), message);
			break;
		default:
			CHECK_FAIL(L"RpcJsonDispatcherClient received an unknown request type.");
		}
		FlushChannel();
	}

	void RpcJsonDispatcherClient::PushReceivedMessage(vint senderClientId, JsonPackage message)
	{
		SPIN_LOCK(lockMessages)
		{
			messages.Add({ senderClientId, message });
		}
		semaphoreMessages.Release();
	}

	RpcJsonDispatcherClient::ReceivedJsonMessage RpcJsonDispatcherClient::PopReceivedMessage()
	{
		semaphoreMessages.Wait();
		ReceivedJsonMessage result;
		SPIN_LOCK(lockMessages)
		{
			CHECK_ERROR(messages.Count() > 0, L"RpcJsonDispatcherClient message queue is unexpectedly empty.");
			result = messages[0];
			messages.RemoveAt(0);
		}
		return result;
	}

	bool RpcJsonDispatcherClient::TryPopBufferedResponse(vint requestId, ReceivedJsonMessage& message)
	{
		SPIN_LOCK(lockMessages)
		{
			for (vint i = 0; i < bufferedResponses.Count(); i++)
			{
				auto item = bufferedResponses[i];
				if (ReadRequestId(item.message) == requestId)
				{
					message = item;
					bufferedResponses.RemoveAt(i);
					return true;
				}
			}
		}
		return false;
	}

	void RpcJsonDispatcherClient::PushBufferedResponse(ReceivedJsonMessage message)
	{
		SPIN_LOCK(lockMessages)
		{
			bufferedResponses.Add(message);
		}
	}

	void RpcJsonDispatcherClient::SendJsonResponse(vint receiverClientId, JsonPackage response)
	{
		if (response)
		{
			CHECK_ERROR(rpcChannel, L"RpcJsonDispatcherClient needs an RPC channel.");
			rpcChannel->SendToClient(receiverClientId, response);
			FlushChannel();
		}
	}

	void RpcJsonDispatcherClient::FlushChannel()
	{
		CHECK_ERROR(rpcChannel, L"RpcJsonDispatcherClient needs an RPC channel.");
		bool disconnected = false;
		rpcChannel->BatchWrite(disconnected);
	}

	void RpcJsonDispatcherClient::ProcessRequestAndSendResponse(vint senderClientId, JsonPackage request)
	{
		auto response = TranslateRequest(request);
		SendJsonResponse(senderClientId, response);
	}

	JsonPackage RpcJsonDispatcherClient::TranslateRequest(JsonPackage request)
	{
		auto rpcMethod = TryReadRpcMethod(request);
		CHECK_ERROR(IsRpcRequest(rpcMethod), L"RpcJsonDispatcherClient expects an RPC request.");

		return IRpcJsonMessageDispatcher::DefaultTranslate(
			request,
			GetRequestType(rpcMethod),
			lifecycle->GetController()->GetObjectOps(),
			lifecycle->GetController()->GetObjectEventOps(),
			lifecycle->GetDispatcher(),
			lifecycle.Obj()
			);
	}

	void RpcJsonDispatcherClient::WaitForServer(JsonChannelClient* channelClient, JsonChannel* channel, const List<WString>& _waitingForServices)
	{
		CHECK_ERROR(channelClient, L"RpcJsonDispatcherClient needs a channel client.");
		PrepareConnection(channel, _waitingForServices);
		channelClient->WaitForServer();
		CHECK_ERROR(channelClient->GetStatus() == ClientStatus::Connected, L"RpcJsonDispatcherClient failed to connect to the server.");
	}

	vint RpcJsonDispatcherClient::ConnectLocalServer(JsonChannelServer* channelServer, Ptr<JsonChannelClient> localClient, JsonChannel* channel, const List<WString>& _waitingForServices)
	{
		CHECK_ERROR(channelServer, L"RpcJsonDispatcherClient needs a channel server.");
		CHECK_ERROR(localClient, L"RpcJsonDispatcherClient needs a local client.");
		PrepareConnection(channel, _waitingForServices);
		auto clientId = channelServer->ConnectLocalClient(localClient);
		CHECK_ERROR(clientId != -1, L"RpcJsonDispatcherClient failed to connect the local client.");
		return clientId;
	}

	void RpcJsonDispatcherClient::Initialize()
	{
		CHECK_ERROR(lifecycle, L"RpcJsonDispatcherClient needs to connect before Initialize.");
		CHECK_ERROR(initialized.load() == 0, L"RpcJsonDispatcherClient can only be initialized once.");
		ProcessCachedIncomingServiceDeclarations();
		lifecycle->Initialize();
		initialized.store(1);
		SendCachedOutgoingServiceDeclarations();
		WaitForExpectedServices();
	}

	IRpcLifecycle* RpcJsonDispatcherClient::GetRpcLifecycle()
	{
		CHECK_ERROR(lifecycle, L"RpcJsonDispatcherClient needs a lifecycle.");
		return lifecycle.Obj();
	}

	IRpcDispatcher* RpcJsonDispatcherClient::GetRpcDispatcher()
	{
		CHECK_ERROR(rpcDispatcher, L"RpcJsonDispatcherClient needs a dispatcher.");
		return rpcDispatcher.Obj();
	}

	vint RpcJsonDispatcherClient::AllocateRequestId()
	{
		return ++nextRequestId;
	}

	JsonPackage RpcJsonDispatcherClient::OnJsonRequest(JsonPackage message, RequestType requestType)
	{
		auto rpcMethod = TryReadRpcMethod(message);
		CHECK_ERROR(rpcMethod != WString::Empty, L"RpcJsonDispatcherClient expects an RPC message.");

		if (requestType == RequestType::BroadcastAndDrop)
		{
			CHECK_ERROR(IsDeclareRemoteServiceRequest(rpcMethod), L"RpcJsonDispatcherClient expects a service declaration.");
			if (initialized.load() == 0)
			{
				SPIN_LOCK(lockServiceDeclarations)
				{
					cachedOutgoingServiceDeclarations.Add(message);
				}
			}
			else
			{
				SendJsonRequest(message, requestType);
			}
			return nullptr;
		}

		CHECK_ERROR(initialized.load() != 0, L"RpcJsonDispatcherClient only accepts service declarations before Initialize.");

		struct ActiveJsonRequest
		{
			atomic_vint& counter;

			ActiveJsonRequest(atomic_vint& _counter)
				: counter(_counter)
			{
				counter++;
			}

			~ActiveJsonRequest()
			{
				counter--;
			}
		};

		ActiveJsonRequest active(activeJsonRequests);
		auto requestId = ReadRequestId(message);
		SendJsonRequest(message, requestType);

		while (true)
		{
			ReceivedJsonMessage item;
			if (!TryPopBufferedResponse(requestId, item))
			{
				item = PopReceivedMessage();
			}
			rpcMethod = TryReadRpcMethod(item.message);
			CHECK_ERROR(rpcMethod != WString::Empty, L"RpcJsonDispatcherClient expects an RPC message.");

			if (IsRpcRequest(rpcMethod))
			{
				ProcessRequestAndSendResponse(item.senderClientId, item.message);
				continue;
			}

			CHECK_ERROR(IsRpcResponse(rpcMethod), L"RpcJsonDispatcherClient expects an RPC request or response.");
			if (ReadRequestId(item.message) == requestId)
			{
				return item.message;
			}

			PushBufferedResponse(item);
		}
	}

	void RpcJsonDispatcherClient::OnRead(vint senderClientId, const JsonPackage& package)
	{
		vint newServerLocalClientId = -1;
		if (TryReadLoginMessage(package, newServerLocalClientId))
		{
			serverLocalClientId.store(newServerLocalClientId);
			eventServerLocalClientId.Signal();
			return;
		}

		auto rpcMethod = TryReadRpcMethod(package);
		CHECK_ERROR(rpcMethod != WString::Empty, L"RpcJsonDispatcherClient expects an RPC message.");

		if (IsDeclareRemoteServiceRequest(rpcMethod))
		{
			if (initialized.load() == 0)
			{
				SPIN_LOCK(lockServiceDeclarations)
				{
					cachedIncomingServiceDeclarations.Add(package);
				}
			}
			else
			{
				ProcessIncomingServiceDeclaration(package);
			}
			return;
		}

		CHECK_ERROR(initialized.load() != 0, L"RpcJsonDispatcherClient only accepts service declarations before Initialize.");

		if (activeJsonRequests.load() > 0)
		{
			PushReceivedMessage(senderClientId, package);
			return;
		}

		if (IsRpcRequest(rpcMethod))
		{
			ScheduleTask(Func<void()>([this, senderClientId, package]()
			{
				ProcessRequestAndSendResponse(senderClientId, package);
			}));
		}
		else
		{
			CHECK_ERROR(IsRpcResponse(rpcMethod), L"RpcJsonDispatcherClient expects an RPC request or response.");
			CHECK_FAIL(L"RpcJsonDispatcherClient received an RPC response while no request is waiting.");
		}
	}

	void RpcJsonDispatcherClient::FinalizeRpc()
	{
		if (lifecycle)
		{
			lifecycle->Finalize();
			lifecycle = nullptr;
			rpcDispatcher = nullptr;
		}
	}

	void RpcJsonDispatcherClient::SetServerLocalClientId(vint clientId)
	{
		CHECK_ERROR(clientId != -1, L"RpcJsonDispatcherClient needs a valid server client id.");
		serverLocalClientId.store(clientId);
		eventServerLocalClientId.Signal();
	}

	void RpcJsonDispatcherClient::NotifyServerClientDisconnected()
	{
		CHECK_ERROR(rpcChannel, L"RpcJsonDispatcherClient needs an RPC channel.");
		WaitForServerClientId();
		rpcChannel->SendToClient(serverLocalClientId.load(), CreateLogoutMessage());
		FlushChannel();
	}

/***********************************************************************
RpcJsonDispatcherClientForTaskQueue
***********************************************************************/

	void RpcJsonDispatcherClientForTaskQueue::ScheduleTask(Func<void()> task)
	{
		taskQueue->QueueTask(task);
	}

	RpcJsonDispatcherClientForTaskQueue::RpcJsonDispatcherClientForTaskQueue(Ptr<TaskQueue> _taskQueue)
		: taskQueue(_taskQueue)
	{
		CHECK_ERROR(taskQueue, L"RpcJsonDispatcherClientForTaskQueue needs a task queue.");
	}
}


/***********************************************************************
.\RPCJSON\WFLIBRARYRPCJSONDISPATCHERSERVER.CPP
***********************************************************************/


namespace vl::rpc_controller::channeling
{
	using namespace vl;
	using namespace vl::collections;
	using namespace vl::glr::json;

	namespace
	{
		Ptr<JsonLiteral> ServerCreateJsonLiteral(JsonLiteralValue value)
		{
			auto node = Ptr(new JsonLiteral);
			node->value = value;
			return node;
		}

		Ptr<JsonString> ServerCreateJsonString(const WString& value)
		{
			auto node = Ptr(new JsonString);
			node->content.value = value;
			return node;
		}

		Ptr<JsonNumber> ServerCreateJsonNumber(vint value)
		{
			auto node = Ptr(new JsonNumber);
			node->content.value = itow(value);
			return node;
		}

		Ptr<JsonArray> ServerCreateJsonArray()
		{
			return Ptr(new JsonArray);
		}

		Ptr<JsonObject> ServerCreateJsonObject()
		{
			return Ptr(new JsonObject);
		}

		Ptr<JsonObject> ServerGetJsonObject(Ptr<JsonNode> node)
		{
			auto object = node.Cast<JsonObject>();
			CHECK_ERROR(object, L"RpcJsonDispatcherServer expects a JSON object.");
			return object;
		}

		Ptr<JsonArray> ServerGetJsonArray(Ptr<JsonNode> node)
		{
			auto array = node.Cast<JsonArray>();
			CHECK_ERROR(array, L"RpcJsonDispatcherServer expects a JSON array.");
			return array;
		}

		void ServerAddJsonObjectField(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);
		}

		void ServerSetJsonObjectField(Ptr<JsonObject> object, const WString& name, Ptr<JsonNode> value)
		{
			for (auto field : object->fields)
			{
				if (field->name.value == name)
				{
					field->value = value;
					return;
				}
			}
			ServerAddJsonObjectField(object, name, value);
		}

		Ptr<JsonNode> ServerFindJsonObjectField(Ptr<JsonObject> object, const WString& name)
		{
			for (auto field : object->fields)
			{
				if (field->name.value == name)
				{
					return field->value;
				}
			}
			return nullptr;
		}

		Ptr<JsonNode> ServerGetJsonObjectField(Ptr<JsonObject> object, const WString& name)
		{
			auto field = ServerFindJsonObjectField(object, name);
			CHECK_ERROR(field, L"RpcJsonDispatcherServer expects a JSON object field.");
			return field;
		}

		WString ServerGetJsonString(Ptr<JsonNode> node)
		{
			auto stringNode = node.Cast<JsonString>();
			CHECK_ERROR(stringNode, L"RpcJsonDispatcherServer expects a JSON string.");
			return stringNode->content.value;
		}

		vint ServerGetJsonInt(Ptr<JsonNode> node)
		{
			auto numberNode = node.Cast<JsonNumber>();
			CHECK_ERROR(numberNode, L"RpcJsonDispatcherServer expects a JSON number.");
			return wtoi(numberNode->content.value);
		}

		bool ServerIsJsonNull(Ptr<JsonNode> node)
		{
			auto literal = node.Cast<JsonLiteral>();
			return literal && literal->value == JsonLiteralValue::Null;
		}

		bool ServerStartsWith(const WString& value, const wchar_t* prefix)
		{
			auto prefixLength = (vint)wcslen(prefix);
			return value.Length() >= prefixLength && wcsncmp(value.Buffer(), prefix, prefixLength) == 0;
		}

		WString ServerTryReadRpcMethod(Ptr<JsonNode> message)
		{
			if (auto object = message.Cast<JsonObject>())
			{
				if (auto field = ServerFindJsonObjectField(object, WString::Unmanaged(L"rpcMethod")))
				{
					if (auto stringNode = field.Cast<JsonString>())
					{
						return stringNode->content.value;
					}
				}
			}
			return WString::Empty;
		}

		bool ServerIsRpcRequest(const WString& rpcMethod)
		{
			return ServerStartsWith(rpcMethod, L"Request:");
		}

		bool ServerIsRpcResponse(const WString& rpcMethod)
		{
			return ServerStartsWith(rpcMethod, L"Response:");
		}

		bool ServerIsBroadcastRequest(const WString& rpcMethod)
		{
			return rpcMethod == WString::Unmanaged(L"Request:IObjectEventOps_InvokeEvent");
		}

		bool ServerIsBroadcastAndDropRequest(const WString& rpcMethod)
		{
			return rpcMethod == WString::Unmanaged(L"Request:IRpcDispatcher_DeclareRemoteService");
		}

		vint ServerReadRequestId(Ptr<JsonNode> message)
		{
			return ServerGetJsonInt(ServerGetJsonObjectField(ServerGetJsonObject(message), WString::Unmanaged(L"rpcRequestId")));
		}

		void ServerWriteRequestId(Ptr<JsonNode> message, vint requestId)
		{
			ServerSetJsonObjectField(ServerGetJsonObject(message), WString::Unmanaged(L"rpcRequestId"), ServerCreateJsonNumber(requestId));
		}

		vint ServerReadSourceClientId(Ptr<JsonNode> message)
		{
			return ServerGetJsonInt(ServerGetJsonObjectField(ServerGetJsonObject(message), WString::Unmanaged(L"sourceClientId")));
		}

		void ServerWriteSourceClientId(Ptr<JsonNode> message, vint clientId)
		{
			ServerSetJsonObjectField(ServerGetJsonObject(message), WString::Unmanaged(L"sourceClientId"), ServerCreateJsonNumber(clientId));
		}

		Ptr<JsonObject> ServerCreateRpcMessage(const WString& rpcMethod, vint requestId, vint sourceClientId)
		{
			auto message = ServerCreateJsonObject();
			ServerAddJsonObjectField(message, WString::Unmanaged(L"rpcMethod"), ServerCreateJsonString(rpcMethod));
			ServerAddJsonObjectField(message, WString::Unmanaged(L"rpcRequestId"), ServerCreateJsonNumber(requestId));
			ServerAddJsonObjectField(message, WString::Unmanaged(L"sourceClientId"), ServerCreateJsonNumber(sourceClientId));
			return message;
		}

		Ptr<JsonObject> ServerCreateLoginMessage(vint serverClientId)
		{
			auto message = ServerCreateJsonObject();
			ServerAddJsonObjectField(message, WString::Unmanaged(L"rpcChannelingSystem"), ServerCreateJsonString(WString::Unmanaged(L"Login")));
			ServerAddJsonObjectField(message, WString::Unmanaged(L"serverClientId"), ServerCreateJsonNumber(serverClientId));
			return message;
		}

		bool ServerTryReadLogoutMessage(Ptr<JsonNode> message)
		{
			if (auto object = message.Cast<JsonObject>())
			{
				auto systemField = ServerFindJsonObjectField(object, WString::Unmanaged(L"rpcChannelingSystem"));
				return systemField && ServerGetJsonString(systemField) == WString::Unmanaged(L"Logout");
			}
			return false;
		}

		bool ServerIsBroadcastReady(Ptr<RpcJsonDispatcherServer::PendingBroadcast> pending)
		{
			for (auto clientId : pending->expectedClientIds)
			{
				if (!pending->responses.Keys().Contains(clientId))
				{
					return false;
				}
			}
			return true;
		}
	}

/***********************************************************************
RpcJsonDispatcherServer
***********************************************************************/

	RpcJsonDispatcherServer::RpcJsonDispatcherServer(JsonChannelClient* _serverClient, JsonChannel* channel)
	{
		CHECK_ERROR(_serverClient, L"RpcJsonDispatcherServer needs a server channel client.");
		CHECK_ERROR(channel, L"RpcJsonDispatcherServer needs an RPC channel.");
		serverClient = _serverClient;
		rpcChannel = channel;
		rpcChannel->Initialize(this);
	}

	vint RpcJsonDispatcherServer::AllocateRequestId()
	{
		return ++nextRequestId;
	}

	WString RpcJsonDispatcherServer::MakeBroadcastKey(vint clientId, vint requestId)
	{
		return itow(clientId) + WString::Unmanaged(L":") + itow(requestId);
	}

	JsonPackage RpcJsonDispatcherServer::CreateBroadcastResponse(vint sourceClientId, vint targetClientId, vint requestId, Ptr<PendingBroadcast> pending)
	{
		auto response = ServerCreateRpcMessage(WString::Unmanaged(L"Response:Broadcast_Response"), requestId, sourceClientId);
		ServerAddJsonObjectField(response, WString::Unmanaged(L"targetClientId"), ServerCreateJsonNumber(targetClientId));

		if (pending && pending->hasNonNullResponse)
		{
			auto consolidated = ServerCreateJsonArray();
			for (auto clientId : pending->expectedClientIds)
			{
				auto index = pending->responses.Keys().IndexOf(clientId);
				if (index != -1)
				{
					auto responseObject = ServerGetJsonObject(pending->responses.Values()[index]);
					auto responseField = ServerFindJsonObjectField(responseObject, WString::Unmanaged(L"response"));
					if (responseField && !ServerIsJsonNull(responseField))
					{
						auto array = ServerGetJsonArray(responseField);
						for (auto item : array->items)
						{
							consolidated->items.Add(item);
						}
					}
				}
			}
			ServerAddJsonObjectField(response, WString::Unmanaged(L"response"), consolidated);
		}
		else
		{
			ServerAddJsonObjectField(response, WString::Unmanaged(L"response"), ServerCreateJsonLiteral(JsonLiteralValue::Null));
		}
		return response;
	}

	RpcJsonDispatcherServer::CompletedBroadcast RpcJsonDispatcherServer::CompleteBroadcastLocked(const WString& key)
	{
		auto pending = pendingBroadcasts[key];
		auto serverClientId = GetServerClientId();
		CompletedBroadcast completed;
		completed.originalClientId = pending->originalClientId;
		completed.response = CreateBroadcastResponse(serverClientId, pending->originalClientId, pending->originalRequestId, pending);

		redirectedBroadcasts.Remove(pending->redirectedRequestId);
		pendingBroadcasts.Remove(key);
		return completed;
	}

	void RpcJsonDispatcherServer::DeliverCompletedBroadcast(const CompletedBroadcast& completed)
	{
		if (completed.response)
		{
			SendJsonResponse(completed.originalClientId, completed.response);
		}
	}

	JsonPackage RpcJsonDispatcherServer::StartBroadcast(vint originalClientId, vint originalRequestId, JsonPackage message)
	{
		auto serverClientId = GetServerClientId();
		auto redirectedRequestId = AllocateRequestId();

		copy_visitor::AstVisitor copier;
		auto redirectedMessage = copier.CopyNode(message.Obj());
		ServerWriteRequestId(redirectedMessage, redirectedRequestId);
		ServerWriteSourceClientId(redirectedMessage, serverClientId);

		JsonPackage immediateResponse;
		bool shouldFlush = false;
		List<vint> blockedReceivers;
		auto pending = Ptr(new PendingBroadcast);
		pending->originalClientId = originalClientId;
		pending->originalRequestId = originalRequestId;
		pending->redirectedRequestId = redirectedRequestId;

		SPIN_LOCK(lockBroadcasts)
		{
			for (auto clientId : connectedClientIds)
			{
				if (clientId != originalClientId)
				{
					pending->expectedClientIds.Add(clientId);
				}
			}

			if (pending->expectedClientIds.Count() == 0)
			{
				immediateResponse = CreateBroadcastResponse(serverClientId, originalClientId, originalRequestId, nullptr);
			}
			else
			{
				auto key = MakeBroadcastKey(originalClientId, originalRequestId);
				pendingBroadcasts.Add(key, pending);
				redirectedBroadcasts.Add(redirectedRequestId, key);

				if (connectedClientIds.Contains(originalClientId))
				{
					blockedReceivers.Add(originalClientId);
				}
				CHECK_ERROR(rpcChannel, L"RpcJsonDispatcherServer needs an RPC channel.");
				rpcChannel->BroadcastFromClient(redirectedMessage, blockedReceivers);
				shouldFlush = true;
			}
		}

		if (shouldFlush)
		{
			FlushChannel();
		}
		return immediateResponse;
	}

	void RpcJsonDispatcherServer::StartBroadcastAndDrop(vint originalClientId, JsonPackage message)
	{
		List<vint> blockedReceivers;
		SPIN_LOCK(lockBroadcasts)
		{
			if (connectedClientIds.Contains(originalClientId))
			{
				blockedReceivers.Add(originalClientId);
			}
			CHECK_ERROR(rpcChannel, L"RpcJsonDispatcherServer needs an RPC channel.");
			rpcChannel->BroadcastFromClient(message, blockedReceivers);
		}
		FlushChannel();
	}

	bool RpcJsonDispatcherServer::TryHandleBroadcastResponse(vint senderClientId, JsonPackage response)
	{
		if (ServerTryReadRpcMethod(response) != WString::Unmanaged(L"Response:Broadcast_Response"))
		{
			return false;
		}

		CompletedBroadcast completed;
		auto redirectedRequestId = ServerReadRequestId(response);
		bool handled = false;

		SPIN_LOCK(lockBroadcasts)
		{
			auto index = redirectedBroadcasts.Keys().IndexOf(redirectedRequestId);
			if (index != -1)
			{
				handled = true;
				auto key = redirectedBroadcasts.Values()[index];
				auto pending = pendingBroadcasts[key];

				if (pending->expectedClientIds.Contains(senderClientId))
				{
					auto responseObject = ServerGetJsonObject(response);
					auto responseField = ServerFindJsonObjectField(responseObject, WString::Unmanaged(L"response"));
					if (responseField && !ServerIsJsonNull(responseField))
					{
						pending->hasNonNullResponse = true;
					}
					pending->responses.Set(senderClientId, response);

					if (ServerIsBroadcastReady(pending))
					{
						completed = CompleteBroadcastLocked(key);
					}
				}
			}
		}

		DeliverCompletedBroadcast(completed);
		return handled;
	}

	void RpcJsonDispatcherServer::HandleServiceDeclaration(vint senderClientId, JsonPackage request)
	{
		SPIN_LOCK(lockBroadcasts)
		{
			cachedServiceDeclarations.Add(request);
		}
		StartBroadcastAndDrop(senderClientId, request);
	}

	void RpcJsonDispatcherServer::SendLoginMessages(vint clientId)
	{
		List<JsonPackage> declarations;
		SPIN_LOCK(lockBroadcasts)
		{
			for (auto request : cachedServiceDeclarations)
			{
				declarations.Add(request);
			}
		}

		CHECK_ERROR(rpcChannel, L"RpcJsonDispatcherServer needs an RPC channel.");
		rpcChannel->SendToClient(clientId, ServerCreateLoginMessage(GetServerClientId()));
		for (auto request : declarations)
		{
			rpcChannel->SendToClient(clientId, request);
		}
		FlushChannel();
	}

	void RpcJsonDispatcherServer::SendJsonResponse(vint receiverClientId, JsonPackage response)
	{
		CHECK_ERROR(rpcChannel, L"RpcJsonDispatcherServer needs an RPC channel.");
		rpcChannel->SendToClient(receiverClientId, response);
		FlushChannel();
	}

	void RpcJsonDispatcherServer::FlushChannel()
	{
		CHECK_ERROR(rpcChannel, L"RpcJsonDispatcherServer needs an RPC channel.");
		bool disconnected = false;
		rpcChannel->BatchWrite(disconnected);
	}

	bool RpcJsonDispatcherServer::HasServerClientId()
	{
		return serverClient->GetClientId() != -1;
	}

	void RpcJsonDispatcherServer::RegisterClient(vint clientId)
	{
		CHECK_ERROR(clientId != -1, L"RpcJsonDispatcherServer needs a valid client id.");
		CHECK_ERROR(HasServerClientId(), L"RpcJsonDispatcherServer needs its server local client to connect first.");

		SPIN_LOCK(lockBroadcasts)
		{
			if (!connectedClientIds.Contains(clientId))
			{
				connectedClientIds.Add(clientId);
			}
		}

		ScheduleTask(Func<void()>([this, clientId]()
		{
			SendLoginMessages(clientId);
		}));
	}

	void RpcJsonDispatcherServer::DisconnectClient(vint clientId)
	{
		if (clientId == GetServerClientId())
		{
			return;
		}

		List<CompletedBroadcast> completedBroadcasts;
		SPIN_LOCK(lockBroadcasts)
		{
			if (connectedClientIds.Contains(clientId))
			{
				connectedClientIds.Remove(clientId);
			}

			for (vint i = pendingBroadcasts.Count(); i > 0; i--)
			{
				auto index = i - 1;
				auto key = pendingBroadcasts.Keys().Get(index);
				auto pending = pendingBroadcasts.Values().Get(index);
				auto expectedIndex = pending->expectedClientIds.IndexOf(clientId);
				if (expectedIndex != -1)
				{
					pending->expectedClientIds.RemoveAt(expectedIndex);
					if (ServerIsBroadcastReady(pending))
					{
						completedBroadcasts.Add(CompleteBroadcastLocked(key));
					}
				}
			}
		}

		for (auto&& completed : completedBroadcasts)
		{
			DeliverCompletedBroadcast(completed);
		}
	}

	vint RpcJsonDispatcherServer::GetServerClientId()
	{
		auto result = serverClient->GetClientId();
		CHECK_ERROR(result != -1, L"RpcJsonDispatcherServer server client has not been connected.");
		return result;
	}

	void RpcJsonDispatcherServer::OnRead(vint senderClientId, const JsonPackage& package)
	{
		if (ServerTryReadLogoutMessage(package))
		{
			DisconnectClient(senderClientId);
			return;
		}

		auto rpcMethod = ServerTryReadRpcMethod(package);
		CHECK_ERROR(rpcMethod != WString::Empty, L"RpcJsonDispatcherServer expects an RPC message.");

		if (ServerIsRpcRequest(rpcMethod))
		{
			auto originalClientId = ServerReadSourceClientId(package);
			CHECK_ERROR(originalClientId == senderClientId, L"RpcJsonDispatcherServer received a request with a mismatched source client id.");

			if (ServerIsBroadcastAndDropRequest(rpcMethod))
			{
				HandleServiceDeclaration(originalClientId, package);
			}
			else if (ServerIsBroadcastRequest(rpcMethod))
			{
				auto immediateResponse = StartBroadcast(originalClientId, ServerReadRequestId(package), package);
				if (immediateResponse)
				{
					SendJsonResponse(originalClientId, immediateResponse);
				}
			}
			else
			{
				CHECK_FAIL(L"RpcJsonDispatcherServer only accepts broadcast requests.");
			}
			return;
		}

		CHECK_ERROR(ServerIsRpcResponse(rpcMethod), L"RpcJsonDispatcherServer expects an RPC request or response.");
		if (!TryHandleBroadcastResponse(senderClientId, package))
		{
			CHECK_FAIL(L"RpcJsonDispatcherServer received an unmatched RPC response.");
		}
	}

/***********************************************************************
RpcJsonDispatcherServerForTaskQueue
***********************************************************************/

	void RpcJsonDispatcherServerForTaskQueue::ScheduleTask(Func<void()> task)
	{
		taskQueue->QueueTask(task);
	}

	RpcJsonDispatcherServerForTaskQueue::RpcJsonDispatcherServerForTaskQueue(JsonChannelClient* _serverClient, JsonChannel* channel, Ptr<TaskQueue> _taskQueue)
		: RpcJsonDispatcherServer(_serverClient, channel)
		, taskQueue(_taskQueue)
	{
		CHECK_ERROR(taskQueue, L"RpcJsonDispatcherServerForTaskQueue needs a task queue.");
	}
}

