MongoSerializer.cpp #1

  • //
  • guest/
  • ququlala/
  • libsprawl/
  • mainline/
  • serialization/
  • mongo/
  • MongoSerializer.cpp
  • View
  • Commits
  • Open Download .zip Download (43 KB)
#include "MongoSerializer.hpp"

namespace sprawl
{
	namespace serialization
	{

		void MongoSerializerBase::Reset()
		{
			if(IsSaving())
			{
				this->m_bIsValid = true;
				for(auto arraybuilder : m_arrayBuilders)
				{
					delete arraybuilder.second;
				}
				m_arrayBuilders.clear();
				for(auto objbuilder : m_objectBuilders)
				{
					delete objbuilder.second;
				}
				m_objectBuilders.clear();
				delete m_builder;
				m_builder = new mongo::BSONObjBuilder();
			}
			else
			{
				m_arrays.clear();
				m_objects.clear();
			}
		}

		void MongoSerializerBase::EnsureVersion()
		{
			if(m_bWithMetadata)
			{
				//This shouldn't happen unless someone's being dumb.
				//And even if they're being dumb, it shouldn't matter unless they're being extra dumb.
				//...but some people are extra dumb.
				if(m_builder->hasField("DataVersion"))
				{
					mongo::BSONObj obj = m_builder->obj();
					obj = obj.removeField("DataVersion");
					delete m_builder;
					m_builder = new mongo::BSONObjBuilder();
					m_builder->appendElements(obj);
				}
				m_builder->append("DataVersion", m_version);
			}
		}

		SerializerBase& MongoSerializerBase::operator%(BinaryData&& var)
		{
			if(!var.PersistToDB || m_disableDepth)
			{
				return *this;
			}
			if(!m_bIsValid)
			{
				m_bError = true;
			}
			if(m_bError)
			{
				return *this;
			}
			if(IsSaving())
			{
				if(!m_arrayBuilders.empty() && m_stateTracker.back() == State::Array)
				{
					mongo::BSONObjBuilder builder;
					builder.appendBinData("binaryData", var.size, mongo::BinDataGeneral, var.val);
					m_arrayBuilders.back().second->append(builder.obj());
				}
				else if(!m_objectBuilders.empty() && m_stateTracker.back() == State::Object)
				{
					if(m_objectBuilders.back().second->hasField(var.name.c_str()))
					{
						SPRAWL_ABORT_MSG("Mongo serialization does not support duplicate keys: key %s was duplicated.", var.name.c_str());
					}
					m_objectBuilders.back().second->appendBinData(var.name.c_str(), var.size, mongo::BinDataGeneral, var.val);
				}
				else
				{
					if(m_builder->hasField(var.name.c_str()))
					{
						SPRAWL_ABORT_MSG("Mongo serialization does not support duplicate keys: key %s was duplicated.", var.name.c_str());
					}
					m_builder->appendBinData(var.name.c_str(), var.size, mongo::BinDataGeneral, var.val);
				}
			}
			else
			{
				const char* str;
				int size = 0;
				if(!m_arrays.empty() && m_stateTracker.back() == State::Array)
				{
					str = m_arrays.back().second.front().Obj()["binaryData"].binData(size);
					m_arrays.back().second.pop_front();
				}
				else if(!m_objects.empty() && m_stateTracker.back() == State::Object)
				{
					str = m_objects.back()[var.name.c_str()].binData(size);
				}
				else
				{
					str = m_obj[var.name.c_str()].binData(size);
				}
				if(var.size != (uint32_t)size)
				{
					m_bError = true;
					return *this;
				}
				memcpy(var.val, str, size);
			}
			return *this;
		}

		uint32_t MongoSerializerBase::StartObject(String const& str, bool PersistToDB)
		{
			if(m_disableDepth || !PersistToDB)
			{
				m_disableDepth++;
				return 0;
			}
			if(!m_bIsValid)
			{
				m_bError = true;
			}
			if(m_bError)
			{
				return 0;
			}
			if(IsSaving())
			{
				//Array fields don't care about name.
				if(!m_objectBuilders.empty() && m_stateTracker.back() == State::Object)
				{
					if(m_objectBuilders.back().second->hasField(str.c_str()))
					{
						SPRAWL_ABORT_MSG("Mongo serialization does not support duplicate keys: key %s was duplicated.", str.c_str());
					}
				}
				else if(m_arrayBuilders.empty() || m_stateTracker.empty() || m_stateTracker.back() != State::Array)
				{
					if(m_builder->hasField(str.c_str()))
					{
						SPRAWL_ABORT_MSG("Mongo serialization does not support duplicate keys: key %s was duplicated.", str.c_str());
					}
				}
				m_objectBuilders.push_back(std::make_pair(str, new mongo::BSONObjBuilder()));
				m_stateTracker.push_back(State::Object);
				return 0; //doesn't matter.
			}
			else
			{
				if(!m_arrays.empty() && !m_stateTracker.empty() && m_stateTracker.back() == State::Array && m_arrays.back().first == str)
				{
					mongo::BSONObj o = m_arrays.back().second.front().Obj();
					m_arrays.back().second.pop_front();
					m_objects.push_back(o);
				}
				else if(!m_objects.empty() && !m_stateTracker.empty() && m_stateTracker.back() == State::Object)
				{
					mongo::BSONObj o = m_objects.back();
					m_objects.push_back(o[str.c_str()].Obj());
				}
				else
				{
					m_objects.push_back(m_obj[str.c_str()].Obj());
				}
				m_stateTracker.push_back(State::Object);
				std::list<mongo::BSONElement> elements;
				m_objects.back().elems(elements);
				m_elementList.push_back(elements);
				return m_objects.back().nFields();
			}
		}

		void MongoSerializerBase::EndObject()
		{
			if(m_disableDepth)
			{
				m_disableDepth--;
				return;
			}
			m_stateTracker.pop_back();
			if(!m_bIsValid)
			{
				m_bError = true;
			}
			if(m_bError)
			{
				return;
			}
			if(IsSaving())
			{
				sprawl::String key = m_objectBuilders.back().first;
				mongo::BSONObj o = m_objectBuilders.back().second->obj();
				delete m_objectBuilders.back().second;
				m_objectBuilders.pop_back();
				if(!m_arrayBuilders.empty() && !m_stateTracker.empty() && m_stateTracker.back() == State::Array)
				{
					m_arrayBuilders.back().second->append(o);
				}
				else if(!m_objectBuilders.empty() && !m_stateTracker.empty() && m_stateTracker.back() == State::Object)
				{
					m_objectBuilders.back().second->append(key.c_str(), o);
				}
				else
				{
					m_builder->append(key.c_str(), o);
				}
			}
			else
			{
				m_objects.pop_back();
				m_elementList.pop_back();
			}
		}

		void MongoSerializerBase::StartArray(String const& str, uint32_t& size, bool PersistToDB)
		{
			if(m_disableDepth || !PersistToDB)
			{
				m_disableDepth++;
				return;
			}
			if(!m_bIsValid)
			{
				m_bError = true;
			}
			if(m_bError)
			{
				return;
			}
			if(IsSaving())
			{
				//Array fields don't care about name.
				if(!m_objectBuilders.empty() && m_stateTracker.back() == State::Object)
				{
					if(m_objectBuilders.back().second->hasField(str.c_str()))
					{
						SPRAWL_ABORT_MSG("Mongo serialization does not support duplicate keys: key %s was duplicated.", str.c_str());
					}
				}
				else if(m_arrayBuilders.empty() || m_stateTracker.empty() || m_stateTracker.back() != State::Array)
				{
					if(m_builder->hasField(str.c_str()))
					{
						SPRAWL_ABORT_MSG("Mongo serialization does not support duplicate keys: key %s was duplicated.", str.c_str());
					}
				}
				m_arrayBuilders.push_back(std::make_pair(str, new mongo::BSONArrayBuilder()));
			}
			else
			{
				if(!m_arrays.empty() && !m_stateTracker.empty() && m_stateTracker.back() == State::Array && m_arrays.back().first == str)
				{
					std::vector<mongo::BSONElement> elements = m_arrays.back().second.front().Array();
					m_arrays.back().second.pop_front();
					m_arrays.push_back(std::make_pair(str, std::deque<mongo::BSONElement>(elements.begin(), elements.end())));
					size = elements.size();
				}
				else if(!m_objects.empty() && !m_stateTracker.empty() && m_stateTracker.back() == State::Object)
				{
					mongo::BSONObj o = m_objects.back();
					std::vector<mongo::BSONElement> elements = o[str.c_str()].Array();
					m_arrays.push_back(std::make_pair(str, std::deque<mongo::BSONElement>(elements.begin(), elements.end())));
					size = elements.size();
				}
				else
				{
					std::vector<mongo::BSONElement> elements = m_obj[str.c_str()].Array();
					m_arrays.push_back(std::make_pair(str, std::deque<mongo::BSONElement>(elements.begin(), elements.end())));
					size = elements.size();
				}
			}
			m_stateTracker.push_back(State::Array);
		}

		void MongoSerializerBase::EndArray()
		{
			if(m_disableDepth)
			{
				m_disableDepth--;
				return;
			}
			m_stateTracker.pop_back();
			if(!m_bIsValid)
			{
				m_bError = true;
			}
			if(m_bError)
			{
				return;
			}
			if(IsSaving())
			{
				sprawl::String key = m_arrayBuilders.back().first;
				mongo::BSONArray arr = m_arrayBuilders.back().second->arr();
				delete m_arrayBuilders.back().second;
				m_arrayBuilders.pop_back();
				if(!m_arrayBuilders.empty() && !m_stateTracker.empty() && m_stateTracker.back() == State::Array)
				{
					m_arrayBuilders.back().second->append(arr);
				}
				else if(!m_objectBuilders.empty() && !m_stateTracker.empty() && m_stateTracker.back() == State::Object)
				{
					m_objectBuilders.back().second->append(key.c_str(), arr);
				}
				else
				{
					m_builder->append(key.c_str(), arr);
				}
			}
			else
			{
				m_arrays.pop_back();
			}
		}

		String MongoSerializerBase::GetNextKey()
		{
			if(IsSaving())
			{
				return "";
			}
			if(!m_stateTracker.empty())
			{
				if(!m_arrays.empty() && m_stateTracker.back() == State::Array)
				{
					return "";
				}
			}
			/*else if(!m_objects.empty() && m_stateTracker.back() == State::Object)
					{
						return m_objects.back().firstElementFieldName();
					}
					else
					{
						m_bError = true;
						return;
					}
				}
				else
				{
					if(m_obj.nFields() == 0)
					{
						m_bError = true;
						return;
					}
					return m_obj.firstElementFieldName();
				}*/
			if(!m_elementList.empty())
			{
				sprawl::String ret(m_elementList.back().front().fieldName());
				m_elementList.back().pop_front();
				return ret;
			}
			return "";
		}

		MongoSerializerBase::~MongoSerializerBase()
		{
			for(auto arraybuilder : m_arrayBuilders)
			{
				delete arraybuilder.second;
			}
			m_arrayBuilders.clear();
			for(auto objbuilder : m_objectBuilders)
			{
				delete objbuilder.second;
			}
			delete m_builder;
		}

		void MongoSerializerBase::serialize(String* var, const uint32_t, String const& name, bool PersistToDB)
		{
			if(!PersistToDB || m_disableDepth)
			{
				return;
			}
			if(!m_bIsValid)
			{
				m_bError = true;
			}
			if(m_bError)
			{
				return;
			}
			if(IsSaving())
			{
				if(!m_arrayBuilders.empty() && m_stateTracker.back() == State::Array)
				{
					m_arrayBuilders.back().second->append(var->toStdString());
				}
				else if(!m_objectBuilders.empty() && m_stateTracker.back() == State::Object)
				{
					if(m_objectBuilders.back().second->hasField(name.c_str()))
					{
						SPRAWL_ABORT_MSG("Mongo serialization does not support duplicate keys: key %s was duplicated.", name.c_str());
					}
					m_objectBuilders.back().second->append(name.c_str(), var->toStdString());
				}
				else
				{
					if(m_builder->hasField(name.c_str()))
					{
						SPRAWL_ABORT_MSG("Mongo serialization does not support duplicate keys: key %s was duplicated.", name.c_str());
					}
					m_builder->append(name.c_str(), var->toStdString());
				}
			}
			else
			{
				if(!m_arrays.empty() && m_stateTracker.back() == State::Array)
				{
					*var = m_arrays.back().second.front().String();
					m_arrays.back().second.pop_front();
				}
				else if(!m_objects.empty() && m_stateTracker.back() == State::Object)
				{
					*var = m_objects.back()[name.c_str()].String();
				}
				else
				{
					*var = m_obj[name.c_str()].String();
				}
			}
		}

		void MongoSerializerBase::serialize(std::string* var, const uint32_t, String const& name, bool PersistToDB)
		{
			if(!PersistToDB || m_disableDepth)
			{
				return;
			}
			if(!m_bIsValid)
			{
				m_bError = true;
			}
			if(m_bError)
			{
				return;
			}
			if(IsSaving())
			{
				if(!m_arrayBuilders.empty() && m_stateTracker.back() == State::Array)
				{
					m_arrayBuilders.back().second->append(*var);
				}
				else if(!m_objectBuilders.empty() && m_stateTracker.back() == State::Object)
				{
					if(m_objectBuilders.back().second->hasField(name.c_str()))
					{
						SPRAWL_ABORT_MSG("Mongo serialization does not support duplicate keys: key %s was duplicated.", name.c_str());
					}
					m_objectBuilders.back().second->append(name.c_str(), *var);
				}
				else
				{
					if(m_builder->hasField(name.c_str()))
					{
						SPRAWL_ABORT_MSG("Mongo serialization does not support duplicate keys: key %s was duplicated.", name.c_str());
					}
					m_builder->append(name.c_str(), *var);
				}
			}
			else
			{
				if(!m_arrays.empty() && m_stateTracker.back() == State::Array)
				{
					*var = m_arrays.back().second.front().String();
					m_arrays.back().second.pop_front();
				}
				else if(!m_objects.empty() && m_stateTracker.back() == State::Object)
				{
					*var = m_objects.back()[name.c_str()].String();
				}
				else
				{
					*var = m_obj[name.c_str()].String();
				}
			}
		}

		void MongoSerializerBase::serialize(unsigned char* var, const uint32_t, String const& name, bool PersistToDB)
		{
			if(!PersistToDB || m_disableDepth)
			{
				return;
			}
			if(!m_bIsValid)
			{
				m_bError = true;
			}
			if(m_bError)
			{
				return;
			}
			if(IsSaving())
			{
				if(!m_arrayBuilders.empty() && m_stateTracker.back() == State::Array)
				{
					m_arrayBuilders.back().second->append(*var);
				}
				else if(!m_objectBuilders.empty() && m_stateTracker.back() == State::Object)
				{
					if(m_objectBuilders.back().second->hasField(name.c_str()))
					{
						SPRAWL_ABORT_MSG("Mongo serialization does not support duplicate keys: key %s was duplicated.", name.c_str());
					}
					m_objectBuilders.back().second->append(name.c_str(), *var);
				}
				else
				{
					if(m_builder->hasField(name.c_str()))
					{
						SPRAWL_ABORT_MSG("Mongo serialization does not support duplicate keys: key %s was duplicated.", name.c_str());
					}
					m_builder->append(name.c_str(), *var);
				}
			}
			else
			{
				std::string str;
				if(!m_arrays.empty() && m_stateTracker.back() == State::Array)
				{
					str = m_arrays.back().second.front().String();
					m_arrays.back().second.pop_front();
				}
				else if(!m_objects.empty() && m_stateTracker.back() == State::Object)
				{
					str = m_objects.back()[name.c_str()].String();
				}
				else
				{
					str = m_obj[name.c_str()].String();
				}
				strcpy((char*)var, str.c_str());
			}
		}

		void MongoSerializerBase::serialize(unsigned short* var, const uint32_t bytes, String const& name, bool PersistToDB)
		{
			if(!PersistToDB || m_disableDepth)
			{
				return;
			}
			if(!m_bIsValid)
			{
				m_bError = true;
			}
			if(m_bError)
			{
				return;
			}
			bool bIsArray = false;
			uint32_t size = 0;
			if(bytes != sizeof(unsigned short int))
			{
				size = bytes/sizeof(unsigned short int);
				bIsArray = true;
				StartArray(name, size, PersistToDB);
			}
			if(IsSaving())
			{
				if(!m_arrayBuilders.empty() && m_stateTracker.back() == State::Array)
				{
					if(bIsArray)
					{
						for(uint32_t i=0; i<size; i++)
						{
							m_arrayBuilders.back().second->append(var[i]);
						}
					}
					else
					{
						m_arrayBuilders.back().second->append(*var);
					}
				}
				else if(!m_objectBuilders.empty() && m_stateTracker.back() == State::Object)
				{
					if(m_objectBuilders.back().second->hasField(name.c_str()))
					{
						SPRAWL_ABORT_MSG("Mongo serialization does not support duplicate keys: key %s was duplicated.", name.c_str());
					}
					m_objectBuilders.back().second->append(name.c_str(), *var);
				}
				else
				{
					if(m_builder->hasField(name.c_str()))
					{
						SPRAWL_ABORT_MSG("Mongo serialization does not support duplicate keys: key %s was duplicated.", name.c_str());
					}
					m_builder->append(name.c_str(), *var);
				}
			}
			else
			{
				if(!m_arrays.empty() && m_stateTracker.back() == State::Array)
				{
					if(bIsArray)
					{
						for(uint32_t i=0; i<size; i++)
						{
							var[i] = (unsigned short)m_arrays.back().second.front().Int();
							m_arrays.back().second.pop_front();
						}
					}
					else
					{
						*var = (unsigned short)m_arrays.back().second.front().Int();
						m_arrays.back().second.pop_front();
					}
				}
				else if(!m_objects.empty() && m_stateTracker.back() == State::Object)
				{
					*var = (unsigned short)m_objects.back()[name.c_str()].Int();
				}
				else
				{
					*var = (unsigned short)m_obj[name.c_str()].Int();
				}
			}
			if(bIsArray)
			{
				EndArray();
			}
		}

		void MongoSerializerBase::serialize(unsigned long long* var, const uint32_t bytes, String const& name, bool PersistToDB)
		{
			if(!PersistToDB || m_disableDepth)
			{
				return;
			}
			if(!m_bIsValid)
			{
				m_bError = true;
			}
			if(m_bError)
			{
				return;
			}
			bool bIsArray = false;
			uint32_t size = 0;
			if(bytes != sizeof(unsigned long long int))
			{
				size = bytes/sizeof(unsigned long long int);
				bIsArray = true;
				StartArray(name, size, PersistToDB);
			}
			if(IsSaving())
			{
				if(!m_arrayBuilders.empty() && m_stateTracker.back() == State::Array)
				{
					if(bIsArray)
					{
						for(uint32_t i=0; i<size; i++)
						{
							m_arrayBuilders.back().second->append((long long int)var[i]);
						}
					}
					else
					{
						m_arrayBuilders.back().second->append((long long int)*var);
					}
				}
				else if(!m_objectBuilders.empty() && m_stateTracker.back() == State::Object)
				{
					if(m_objectBuilders.back().second->hasField(name.c_str()))
					{
						SPRAWL_ABORT_MSG("Mongo serialization does not support duplicate keys: key %s was duplicated.", name.c_str());
					}
					m_objectBuilders.back().second->append(name.c_str(), (long long int)*var);
				}
				else
				{
					if(m_builder->hasField(name.c_str()))
					{
						SPRAWL_ABORT_MSG("Mongo serialization does not support duplicate keys: key %s was duplicated.", name.c_str());
					}
					m_builder->append(name.c_str(), (long long int)*var);
				}
			}
			else
			{
				if(!m_arrays.empty() && m_stateTracker.back() == State::Array)
				{
					if(bIsArray)
					{
						for(uint32_t i=0; i<size; i++)
						{
							var[i] = m_arrays.back().second.front().Long();
							m_arrays.back().second.pop_front();
						}
					}
					else
					{
						*var = m_arrays.back().second.front().Long();
						m_arrays.back().second.pop_front();
					}
				}
				else if(!m_objects.empty() && m_stateTracker.back() == State::Object)
				{
					*var = m_objects.back()[name.c_str()].Long();
				}
				else
				{
					*var = m_obj[name.c_str()].Long();
				}
			}
			if(bIsArray)
			{
				EndArray();
			}
		}

		void MongoSerializerBase::serialize(unsigned long* var, const uint32_t bytes, String const& name, bool PersistToDB)
		{
			if(!PersistToDB || m_disableDepth)
			{
				return;
			}
			if(!m_bIsValid)
			{
				m_bError = true;
			}
			if(m_bError)
			{
				return;
			}
			bool bIsArray = false;
			uint32_t size = 0;
			if(bytes != sizeof(unsigned long int))
			{
				size = bytes/sizeof(unsigned long int);
				bIsArray = true;
				StartArray(name, size, PersistToDB);
			}
			if(IsSaving())
			{
				if(!m_arrayBuilders.empty() && m_stateTracker.back() == State::Array)
				{
					if(bIsArray)
					{
						for(uint32_t i=0; i<size; i++)
						{
							m_arrayBuilders.back().second->append((long long int)var[i]);
						}
					}
					else
					{
						m_arrayBuilders.back().second->append((long long int)*var);
					}
				}
				else if(!m_objectBuilders.empty() && m_stateTracker.back() == State::Object)
				{
					if(m_objectBuilders.back().second->hasField(name.c_str()))
					{
						SPRAWL_ABORT_MSG("Mongo serialization does not support duplicate keys: key %s was duplicated.", name.c_str());
					}
					m_objectBuilders.back().second->append(name.c_str(), (long long int)*var);
				}
				else
				{
					if(m_builder->hasField(name.c_str()))
					{
						SPRAWL_ABORT_MSG("Mongo serialization does not support duplicate keys: key %s was duplicated.", name.c_str());
					}
					m_builder->append(name.c_str(), (long long int)*var);
				}
			}
			else
			{
				if(!m_arrays.empty() && m_stateTracker.back() == State::Array)
				{
					if(bIsArray)
					{
						for(uint32_t i=0; i<size; i++)
						{
							var[i] = (unsigned long)m_arrays.back().second.front().Long();
							m_arrays.back().second.pop_front();
						}
					}
					else
					{
						*var = (unsigned long)m_arrays.back().second.front().Long();
						m_arrays.back().second.pop_front();
					}
				}
				else if(!m_objects.empty() && m_stateTracker.back() == State::Object)
				{
					*var = (unsigned long)m_objects.back()[name.c_str()].Long();
				}
				else
				{
					*var = (unsigned long)m_obj[name.c_str()].Long();
				}
			}
			if(bIsArray)
			{
				EndArray();
			}
		}

		void MongoSerializerBase::serialize(unsigned int* var, const uint32_t bytes, String const& name, bool PersistToDB)
		{
			if(!PersistToDB || m_disableDepth)
			{
				return;
			}
			if(!m_bIsValid)
			{
				m_bError = true;
			}
			if(m_bError)
			{
				return;
			}
			bool bIsArray = false;
			uint32_t size = 0;
			if(bytes != sizeof(unsigned int))
			{
				size = bytes/sizeof(unsigned int);
				bIsArray = true;
				StartArray(name, size, PersistToDB);
			}
			if(IsSaving())
			{
				if(!m_arrayBuilders.empty() && m_stateTracker.back() == State::Array)
				{
					if(bIsArray)
					{
						for(uint32_t i=0; i<size; i++)
						{
							m_arrayBuilders.back().second->append(var[i]);
						}
					}
					else
					{
						m_arrayBuilders.back().second->append(*var);
					}
				}
				else if(!m_objectBuilders.empty() && m_stateTracker.back() == State::Object)
				{
					if(m_objectBuilders.back().second->hasField(name.c_str()))
					{
						SPRAWL_ABORT_MSG("Mongo serialization does not support duplicate keys: key %s was duplicated.", name.c_str());
					}
					m_objectBuilders.back().second->append(name.c_str(), *var);
				}
				else
				{
					if(m_builder->hasField(name.c_str()))
					{
						SPRAWL_ABORT_MSG("Mongo serialization does not support duplicate keys: key %s was duplicated.", name.c_str());
					}
					m_builder->append(name.c_str(), *var);
				}
			}
			else
			{
				if(!m_arrays.empty() && m_stateTracker.back() == State::Array)
				{
					if(bIsArray)
					{
						for(uint32_t i=0; i<size; i++)
						{
							var[i] = m_arrays.back().second.front().Int();
							m_arrays.back().second.pop_front();
						}
					}
					else
					{
						*var = m_arrays.back().second.front().Int();
						m_arrays.back().second.pop_front();
					}
				}
				else if(!m_objects.empty() && m_stateTracker.back() == State::Object)
				{
					*var = m_objects.back()[name.c_str()].Int();
				}
				else
				{
					*var = m_obj[name.c_str()].Int();
				}
			}
			if(bIsArray)
			{
				EndArray();
			}
		}

		void MongoSerializerBase::serialize(bool* var, const uint32_t bytes, String const& name, bool PersistToDB)
		{
			if(!PersistToDB || m_disableDepth)
			{
				return;
			}
			if(!m_bIsValid)
			{
				m_bError = true;
			}
			if(m_bError)
			{
				return;
			}
			bool bIsArray = false;
			uint32_t size = 0;
			if(bytes != sizeof(bool))
			{
				size = bytes/sizeof(bool);
				bIsArray = true;
				StartArray(name, size, PersistToDB);
			}
			if(IsSaving())
			{
				if(!m_arrayBuilders.empty() && m_stateTracker.back() == State::Array)
				{
					if(bIsArray)
					{
						for(uint32_t i=0; i<size; i++)
						{
							m_arrayBuilders.back().second->append(var[i]);
						}
					}
					else
					{
						m_arrayBuilders.back().second->append(*var);
					}
				}
				else if(!m_objectBuilders.empty() && m_stateTracker.back() == State::Object)
				{
					if(m_objectBuilders.back().second->hasField(name.c_str()))
					{
						SPRAWL_ABORT_MSG("Mongo serialization does not support duplicate keys: key %s was duplicated.", name.c_str());
					}
					m_objectBuilders.back().second->append(name.c_str(), *var);
				}
				else
				{
					if(m_builder->hasField(name.c_str()))
					{
						SPRAWL_ABORT_MSG("Mongo serialization does not support duplicate keys: key %s was duplicated.", name.c_str());
					}
					m_builder->append(name.c_str(), *var);
				}
			}
			else
			{
				if(!m_arrays.empty() && m_stateTracker.back() == State::Array)
				{
					if(bIsArray)
					{
						for(uint32_t i=0; i<size; i++)
						{
							var[i] = m_arrays.back().second.front().Bool();
							m_arrays.back().second.pop_front();
						}
					}
					else
					{
						*var = m_arrays.back().second.front().Bool();
						m_arrays.back().second.pop_front();
					}
				}
				else if(!m_objects.empty() && m_stateTracker.back() == State::Object)
				{
					*var = m_objects.back()[name.c_str()].Bool();
				}
				else
				{
					*var = m_obj[name.c_str()].Bool();
				}
			}
			if(bIsArray)
			{
				EndArray();
			}
		}

		void MongoSerializerBase::serialize(double* var, const uint32_t bytes, String const& name, bool PersistToDB)
		{
			if(!PersistToDB || m_disableDepth)
			{
				return;
			}
			if(!m_bIsValid)
			{
				m_bError = true;
			}
			if(m_bError)
			{
				return;
			}
			bool bIsArray = false;
			uint32_t size = 0;
			if(bytes != sizeof(double))
			{
				size = bytes/sizeof(double);
				bIsArray = true;
				StartArray(name, size, PersistToDB);
			}
			if(IsSaving())
			{
				if(!m_arrayBuilders.empty() && m_stateTracker.back() == State::Array)
				{
					if(bIsArray)
					{
						for(uint32_t i=0; i<size; i++)
						{
							m_arrayBuilders.back().second->append(var[i]);
						}
					}
					else
					{
						m_arrayBuilders.back().second->append(*var);
					}
				}
				else if(!m_objectBuilders.empty() && m_stateTracker.back() == State::Object)
				{
					if(m_objectBuilders.back().second->hasField(name.c_str()))
					{
						SPRAWL_ABORT_MSG("Mongo serialization does not support duplicate keys: key %s was duplicated.", name.c_str());
					}
					m_objectBuilders.back().second->append(name.c_str(), *var);
				}
				else
				{
					if(m_builder->hasField(name.c_str()))
					{
						SPRAWL_ABORT_MSG("Mongo serialization does not support duplicate keys: key %s was duplicated.", name.c_str());
					}
					m_builder->append(name.c_str(), *var);
				}
			}
			else
			{
				if(!m_arrays.empty() && m_stateTracker.back() == State::Array)
				{
					if(bIsArray)
					{
						for(uint32_t i=0; i<size; i++)
						{
							var[i] = m_arrays.back().second.front().Double();
							m_arrays.back().second.pop_front();
						}
					}
					else
					{
						*var = m_arrays.back().second.front().Double();
						m_arrays.back().second.pop_front();
					}
				}
				else if(!m_objects.empty() && m_stateTracker.back() == State::Object)
				{
					*var = m_objects.back()[name.c_str()].Double();
				}
				else
				{
					*var = m_obj[name.c_str()].Double();
				}
			}
			if(bIsArray)
			{
				EndArray();
			}
		}

		void MongoSerializerBase::serialize(float* var, const uint32_t bytes, String const& name, bool PersistToDB)
		{
			if(!PersistToDB || m_disableDepth)
			{
				return;
			}
			if(!m_bIsValid)
			{
				m_bError = true;
			}
			if(m_bError)
			{
				return;
			}
			bool bIsArray = false;
			uint32_t size = 0;
			if(bytes != sizeof(float))
			{
				size = bytes/sizeof(float);
				bIsArray = true;
				StartArray(name, size, PersistToDB);
			}
			if(IsSaving())
			{
				if(!m_arrayBuilders.empty() && m_stateTracker.back() == State::Array)
				{
					if(bIsArray)
					{
						for(uint32_t i=0; i<size; i++)
						{
							m_arrayBuilders.back().second->append(var[i]);
						}
					}
					else
					{
						m_arrayBuilders.back().second->append(*var);
					}
				}
				else if(!m_objectBuilders.empty() && m_stateTracker.back() == State::Object)
				{
					if(m_objectBuilders.back().second->hasField(name.c_str()))
					{
						SPRAWL_ABORT_MSG("Mongo serialization does not support duplicate keys: key %s was duplicated.", name.c_str());
					}
					m_objectBuilders.back().second->append(name.c_str(), *var);
				}
				else
				{
					if(m_builder->hasField(name.c_str()))
					{
						SPRAWL_ABORT_MSG("Mongo serialization does not support duplicate keys: key %s was duplicated.", name.c_str());
					}
					m_builder->append(name.c_str(), *var);
				}
			}
			else
			{
				if(!m_arrays.empty() && m_stateTracker.back() == State::Array)
				{
					if(bIsArray)
					{
						for(uint32_t i=0; i<size; i++)
						{
							var[i] = (float)m_arrays.back().second.front().Double();
							m_arrays.back().second.pop_front();
						}
					}
					else
					{
						*var = (float)m_arrays.back().second.front().Double();
						m_arrays.back().second.pop_front();
					}
				}
				else if(!m_objects.empty() && m_stateTracker.back() == State::Object)
				{
					*var = (float)m_objects.back()[name.c_str()].Double();
				}
				else
				{
					*var = (float)m_obj[name.c_str()].Double();
				}
			}
			if(bIsArray)
			{
				EndArray();
			}
		}

		void MongoSerializerBase::serialize(char* var, const uint32_t, String const& name, bool PersistToDB)
		{
			if(!PersistToDB || m_disableDepth)
			{
				return;
			}
			if(!m_bIsValid)
			{
				m_bError = true;
			}
			if(m_bError)
			{
				return;
			}
			if(IsSaving())
			{
				if(!m_arrayBuilders.empty() && m_stateTracker.back() == State::Array)
				{
					m_arrayBuilders.back().second->append(*var);
				}
				else if(!m_objectBuilders.empty() && m_stateTracker.back() == State::Object)
				{
					if(m_objectBuilders.back().second->hasField(name.c_str()))
					{
						SPRAWL_ABORT_MSG("Mongo serialization does not support duplicate keys: key %s was duplicated.", name.c_str());
					}
					m_objectBuilders.back().second->append(name.c_str(), *var);
				}
				else
				{
					if(m_builder->hasField(name.c_str()))
					{
						SPRAWL_ABORT_MSG("Mongo serialization does not support duplicate keys: key %s was duplicated.", name.c_str());
					}
					m_builder->append(name.c_str(), *var);
				}
			}
			else
			{
				std::string str;
				if(!m_arrays.empty() && m_stateTracker.back() == State::Array)
				{
					str = m_arrays.back().second.front().String();
					m_arrays.back().second.pop_front();
				}
				else if(!m_objects.empty() && m_stateTracker.back() == State::Object)
				{
					str = m_objects.back()[name.c_str()].String();
				}
				else
				{
					str = m_obj[name.c_str()].String();
				}
				strcpy(var, str.c_str());
			}
		}

		void MongoSerializerBase::serialize(short* var, const uint32_t bytes, String const& name, bool PersistToDB)
		{
			if(!PersistToDB || m_disableDepth)
			{
				return;
			}
			if(!m_bIsValid)
			{
				m_bError = true;
			}
			if(m_bError)
			{
				return;
			}
			bool bIsArray = false;
			uint32_t size = 0;
			if(bytes != sizeof(short int))
			{
				size = bytes/sizeof(short int);
				bIsArray = true;
				StartArray(name, size, PersistToDB);
			}
			if(IsSaving())
			{
				if(!m_arrayBuilders.empty() && m_stateTracker.back() == State::Array)
				{
					if(bIsArray)
					{
						for(uint32_t i=0; i<size; i++)
						{
							m_arrayBuilders.back().second->append(var[i]);
						}
					}
					else
					{
						m_arrayBuilders.back().second->append(*var);
					}
				}
				else if(!m_objectBuilders.empty() && m_stateTracker.back() == State::Object)
				{
					if(m_objectBuilders.back().second->hasField(name.c_str()))
					{
						SPRAWL_ABORT_MSG("Mongo serialization does not support duplicate keys: key %s was duplicated.", name.c_str());
					}
					m_objectBuilders.back().second->append(name.c_str(), *var);
				}
				else
				{
					if(m_builder->hasField(name.c_str()))
					{
						SPRAWL_ABORT_MSG("Mongo serialization does not support duplicate keys: key %s was duplicated.", name.c_str());
					}
					m_builder->append(name.c_str(), *var);
				}
			}
			else
			{
				if(!m_arrays.empty() && m_stateTracker.back() == State::Array)
				{
					if(bIsArray)
					{
						for(uint32_t i=0; i<size; i++)
						{
							var[i] = (short)m_arrays.back().second.front().Int();
							m_arrays.back().second.pop_front();
						}
					}
					else
					{
						*var = (short)m_arrays.back().second.front().Int();
						m_arrays.back().second.pop_front();
					}
				}
				else if(!m_objects.empty() && m_stateTracker.back() == State::Object)
				{
					*var = (short)m_objects.back()[name.c_str()].Int();
				}
				else
				{
					*var = (short)m_obj[name.c_str()].Int();
				}
			}
			if(bIsArray)
			{
				EndArray();
			}
		}

		void MongoSerializerBase::serialize(long long* var, const uint32_t bytes, String const& name, bool PersistToDB)
		{
			if(!PersistToDB || m_disableDepth)
			{
				return;
			}
			if(!m_bIsValid)
			{
				m_bError = true;
			}
			if(m_bError)
			{
				return;
			}
			bool bIsArray = false;
			uint32_t size = 0;
			if(bytes != sizeof(long long int))
			{
				size = bytes/sizeof(long long int);
				bIsArray = true;
				StartArray(name, size, PersistToDB);
			}
			if(IsSaving())
			{
				if(!m_arrayBuilders.empty() && m_stateTracker.back() == State::Array)
				{
					if(bIsArray)
					{
						for(uint32_t i=0; i<size; i++)
						{
							m_arrayBuilders.back().second->append(var[i]);
						}
					}
					else
					{
						m_arrayBuilders.back().second->append(*var);
					}
				}
				else if(!m_objectBuilders.empty() && m_stateTracker.back() == State::Object)
				{
					if(m_objectBuilders.back().second->hasField(name.c_str()))
					{
						SPRAWL_ABORT_MSG("Mongo serialization does not support duplicate keys: key %s was duplicated.", name.c_str());
					}
					m_objectBuilders.back().second->append(name.c_str(), *var);
				}
				else
				{
					if(m_builder->hasField(name.c_str()))
					{
						SPRAWL_ABORT_MSG("Mongo serialization does not support duplicate keys: key %s was duplicated.", name.c_str());
					}
					m_builder->append(name.c_str(), *var);
				}
			}
			else
			{
				if(!m_arrays.empty() && m_stateTracker.back() == State::Array)
				{
					if(bIsArray)
					{
						for(uint32_t i=0; i<size; i++)
						{
							var[i] = m_arrays.back().second.front().Long();
							m_arrays.back().second.pop_front();
						}
					}
					else
					{
						*var = m_arrays.back().second.front().Long();
						m_arrays.back().second.pop_front();
					}
				}
				else if(!m_objects.empty() && m_stateTracker.back() == State::Object)
				{
					*var = m_objects.back()[name.c_str()].Long();
				}
				else
				{
					*var = m_obj[name.c_str()].Long();
				}
			}
			if(bIsArray)
			{
				EndArray();
			}
		}

		void MongoSerializerBase::serialize(long* var, const uint32_t bytes, String const& name, bool PersistToDB)
		{
			if(!PersistToDB || m_disableDepth)
			{
				return;
			}
			if(!m_bIsValid)
			{
				m_bError = true;
			}
			if(m_bError)
			{
				return;
			}
			bool bIsArray = false;
			uint32_t size = 0;
			if(bytes != sizeof(long int))
			{
				size = bytes/sizeof(long int);
				bIsArray = true;
				StartArray(name, size, PersistToDB);
			}
			if(IsSaving())
			{
				if(!m_arrayBuilders.empty() && m_stateTracker.back() == State::Array)
				{
					if(bIsArray)
					{
						for(uint32_t i=0; i<size; i++)
						{
							m_arrayBuilders.back().second->append((long long int)var[i]);
						}
					}
					else
					{
						m_arrayBuilders.back().second->append((long long int)*var);
					}
				}
				else if(!m_objectBuilders.empty() && m_stateTracker.back() == State::Object)
				{
					if(m_objectBuilders.back().second->hasField(name.c_str()))
					{
						SPRAWL_ABORT_MSG("Mongo serialization does not support duplicate keys: key %s was duplicated.", name.c_str());
					}
					m_objectBuilders.back().second->append(name.c_str(), (long long int)*var);
				}
				else
				{
					if(m_builder->hasField(name.c_str()))
					{
						SPRAWL_ABORT_MSG("Mongo serialization does not support duplicate keys: key %s was duplicated.", name.c_str());
					}
					m_builder->append(name.c_str(), (long long int)*var);
				}
			}
			else
			{
				if(!m_arrays.empty() && m_stateTracker.back() == State::Array)
				{
					if(bIsArray)
					{
						for(uint32_t i=0; i<size; i++)
						{
							var[i] = (long)m_arrays.back().second.front().Long();
							m_arrays.back().second.pop_front();
						}
					}
					else
					{
						*var = (long)m_arrays.back().second.front().Long();
						m_arrays.back().second.pop_front();
					}
				}
				else if(!m_objects.empty() && m_stateTracker.back() == State::Object)
				{
					*var = (long)m_objects.back()[name.c_str()].Long();
				}
				else
				{
					*var = (long)m_obj[name.c_str()].Long();
				}
			}
			if(bIsArray)
			{
				EndArray();
			}
		}

		void MongoSerializerBase::serialize(int* var, const uint32_t bytes, String const& name, bool PersistToDB)
		{
			if(!PersistToDB || m_disableDepth)
			{
				return;
			}
			if(!m_bIsValid)
			{
				m_bError = true;
			}
			if(m_bError)
			{
				return;
			}
			bool bIsArray = false;
			uint32_t size = 0;
			if(bytes != sizeof(int))
			{
				size = bytes/sizeof(int);
				bIsArray = true;
				StartArray(name, size, PersistToDB);
			}
			if(IsSaving())
			{
				if(!m_arrayBuilders.empty() && m_stateTracker.back() == State::Array)
				{
					if(bIsArray)
					{
						for(uint32_t i=0; i<size; i++)
						{
							m_arrayBuilders.back().second->append(var[i]);
						}
					}
					else
					{
						m_arrayBuilders.back().second->append(*var);
					}
				}
				else if(!m_objectBuilders.empty() && m_stateTracker.back() == State::Object)
				{
					if(m_objectBuilders.back().second->hasField(name.c_str()))
					{
						SPRAWL_ABORT_MSG("Mongo serialization does not support duplicate keys: key %s was duplicated.", name.c_str());
					}
					m_objectBuilders.back().second->append(name.c_str(), *var);
				}
				else
				{
					if(m_builder->hasField(name.c_str()))
					{
						SPRAWL_ABORT_MSG("Mongo serialization does not support duplicate keys: key %s was duplicated.", name.c_str());
					}
					m_builder->append(name.c_str(), *var);
				}
			}
			else
			{
				if(!m_arrays.empty() && m_stateTracker.back() == State::Array)
				{
					if(bIsArray)
					{
						for(uint32_t i=0; i<size; i++)
						{
							var[i] = m_arrays.back().second.front().Int();
							m_arrays.back().second.pop_front();
						}
					}
					else
					{
						*var = m_arrays.back().second.front().Int();
						m_arrays.back().second.pop_front();
					}
				}
				else if(!m_objects.empty() && m_stateTracker.back() == State::Object)
				{
					*var = m_objects.back()[name.c_str()].Int();
				}
				else
				{
					*var = m_obj[name.c_str()].Int();
				}
			}
			if(bIsArray)
			{
				EndArray();
			}
		}

		void MongoSerializerBase::serialize(mongo::Date_t* var, String const& name, bool PersistToDB)
		{
			if(!PersistToDB || m_disableDepth)
			{
				return;
			}
			if(!m_bIsValid)
			{
				m_bError = true;
			}
			if(m_bError)
			{
				return;
			}
			if(IsSaving())
			{
				if(!m_arrayBuilders.empty() && m_stateTracker.back() == State::Array)
				{
					m_arrayBuilders.back().second->append(*var);
				}
				else if(!m_objectBuilders.empty() && m_stateTracker.back() == State::Object)
				{
					if(m_objectBuilders.back().second->hasField(name.c_str()))
					{
						SPRAWL_ABORT_MSG("Mongo serialization does not support duplicate keys: key %s was duplicated.", name.c_str());
					}
					m_objectBuilders.back().second->append(name.c_str(), *var);
				}
				else
				{
					if(m_builder->hasField(name.c_str()))
					{
						SPRAWL_ABORT_MSG("Mongo serialization does not support duplicate keys: key %s was duplicated.", name.c_str());
					}
					m_builder->append(name.c_str(), *var);
				}
			}
			else
			{
				if(!m_arrays.empty() && m_stateTracker.back() == State::Array)
				{
					*var = m_arrays.back().second.front().Date();
					m_arrays.back().second.pop_front();
				}
				else if(!m_objects.empty() && m_stateTracker.back() == State::Object)
				{
					*var = m_objects.back()[name.c_str()].Date();
				}
				else
				{
					*var = m_obj[name.c_str()].Date();
				}
			}
		}

		void MongoSerializerBase::serialize(mongo::BSONObj* var, String const& name, bool PersistToDB)
		{
			if(!PersistToDB || m_disableDepth)
			{
				return;
			}
			if(!m_bIsValid)
			{
				m_bError = true;
			}
			if(m_bError)
			{
				return;
			}
			if(IsSaving())
			{
				if(!m_arrayBuilders.empty() && m_stateTracker.back() == State::Array)
				{
					m_arrayBuilders.back().second->append(*var);
				}
				else if(!m_objectBuilders.empty() && m_stateTracker.back() == State::Object)
				{
					if(m_objectBuilders.back().second->hasField(name.c_str()))
					{
						SPRAWL_ABORT_MSG("Mongo serialization does not support duplicate keys: key %s was duplicated.", name.c_str());
					}
					m_objectBuilders.back().second->append(name.c_str(), *var);
				}
				else
				{
					if(m_builder->hasField(name.c_str()))
					{
						SPRAWL_ABORT_MSG("Mongo serialization does not support duplicate keys: key %s was duplicated.", name.c_str());
					}
					m_builder->append(name.c_str(), *var);
				}
			}
			else
			{
				if(!m_arrays.empty() && m_stateTracker.back() == State::Array)
				{
					*var = m_arrays.back().second.front().Obj().copy();
					m_arrays.back().second.pop_front();
				}
				else if(!m_objects.empty() && m_stateTracker.back() == State::Object)
				{
					*var = m_objects.back()[name.c_str()].Obj().copy();
				}
				else
				{
					*var = m_obj[name.c_str()].Obj().copy();
				}
			}
		}

		void MongoSerializerBase::serialize(mongo::OID* var, String const& name, bool PersistToDB)
		{
			if(!PersistToDB || m_disableDepth)
			{
				return;
			}
			if(!m_bIsValid)
			{
				m_bError = true;
			}
			if(m_bError)
			{
				return;
			}
			if(IsSaving())
			{
				if(!m_arrayBuilders.empty() && m_stateTracker.back() == State::Array)
				{
					m_arrayBuilders.back().second->append(*var);
				}
				else if(!m_objectBuilders.empty() && m_stateTracker.back() == State::Object)
				{
					if(m_objectBuilders.back().second->hasField(name.c_str()))
					{
						SPRAWL_ABORT_MSG("Mongo serialization does not support duplicate keys: key %s was duplicated.", name.c_str());
					}
					m_objectBuilders.back().second->append(name.c_str(), *var);
				}
				else
				{
					if(m_builder->hasField(name.c_str()))
					{
						SPRAWL_ABORT_MSG("Mongo serialization does not support duplicate keys: key %s was duplicated.", name.c_str());
					}
					m_builder->append(name.c_str(), *var);
				}
			}
			else
			{
				if(!m_arrays.empty() && m_stateTracker.back() == State::Array)
				{
					*var = m_arrays.back().second.front().OID();
					m_arrays.back().second.pop_front();
				}
				else if(!m_objects.empty() && m_stateTracker.back() == State::Object)
				{
					*var = m_objects.back()[name.c_str()].OID();
				}
				else
				{
					*var = m_obj[name.c_str()].OID();
				}
			}
		}

		SerializerBase& operator%(SerializerBase& s, SerializationData<mongo::OID>&& var)
		{
			if(s.IsMongoStream())
			{
				s.serialize(&var.val, var.name, var.PersistToDB);
			}
			else
			{
				if(s.IsLoading())
				{
					std::string str;
					s % prepare_data(str, var.name, var.PersistToDB);
					var.val.init(str);
				}
				else
				{
					s % prepare_data(var.val.str(), var.name, var.PersistToDB);
				}
			}
			return s;
		}

		SerializerBase& operator%(SerializerBase& s, SerializationData<mongo::BSONObj>&& var)
		{
			if(s.IsMongoStream())
			{
				s.serialize(&var.val, var.name, var.PersistToDB);
			}
			else
			{
				if(s.IsLoading())
				{
					sprawl::String str;
					s % prepare_data(str, var.name, var.PersistToDB);
					if(s.IsBinary())
					{
						var.val = mongo::BSONObj(str.c_str()).copy();
					}
					else
					{
						var.val = mongo::fromjson(str.c_str());
					}
				}
				else
				{
					if(s.IsBinary())
					{
						s % prepare_data(sprawl::String(var.val.objdata(), var.val.objsize()), var.name, var.PersistToDB);
					}
					else
					{
						s % prepare_data(var.val.jsonString(), var.name, var.PersistToDB);
					}
				}
			}
			return s;
		}

		SerializerBase& operator%(SerializerBase& s, SerializationData<mongo::Date_t>&& var)
		{
			if(s.IsMongoStream())
			{
				s.serialize(&var.val, var.name, var.PersistToDB);
			}
			else
			{
				if(s.IsLoading())
				{
					int64_t val;
					s % prepare_data(val, var.name, var.PersistToDB);
					var.val = mongo::Date_t(val);
				}
				else
				{
					s % prepare_data(var.val.millis, var.name, var.PersistToDB);
				}
			}
			return s;
		}




	}
}
# Change User Description Committed
#1 23398 ququlala "Forking branch Mainline of shadauxcat-libsprawl to ququlala-libsprawl."
//guest/ShadauxCat/Sprawl/Mainline/serialization/mongo/MongoSerializer.cpp
#2 14783 ShadauxCat Style corrections (placement of const)

#review-14784
#1 11496 ShadauxCat Initial checkin: Current states for csbuild and libSprawl