bool VariantStreamHandler::write(const Variant& v, const NodePtr& node, bool writeType) { // Variant only accepts binary/text streams for streamin/out, so we get to do this fun little stream dance. ResizingMemoryStream s; TextStream ts(s); ts << v; // Get the type to be used - leave it null if we shouldn't write the type, setValueRawData won't write a type const char* nodeTypeName = nullptr; size_t nodeTypeSize = 0; if (writeType) { nodeTypeName = variantName_; nodeTypeSize = strlen(nodeTypeName); } // ResizingMemoryStream is not guaranteed to be null terminated. node->setValueRawData(s.buffer().c_str(), s.buffer().size(), nodeTypeName, nodeTypeSize); node->setHandlerName(handlerName_); auto variantTypeName = this->getReservedNames().variantInternalType; auto typeNode = node->createEmptyChild(variantTypeName, strlen(variantTypeName)); const char* internalTypeName = v.type()->typeId().getName(); typeNode->setValueString(internalTypeName, strlen(internalTypeName)); return true; }
bool CollectionHandler::write(const Variant& v, const NodePtr& node, bool writeType) { node->setHandlerName(handlerName_); if (writeType) { node->setType(collectionName_, strlen(collectionName_)); } bool success = false; Collection c; if (!v.tryCast<Collection>(c)) { return false; } if (c.empty()) { return true; } // Check that the key isn't a collection, since we can't serialize those. if (c.begin().key().canCast<Collection>()) { return false; } // Find and hold on to our handlers std::shared_ptr<SerializationHandler> keyHandler = nullptr; std::shared_ptr<SerializationHandler> valueHandler = nullptr; const MetaType* keyMetaType = MetaType::find(c.keyType().getName()); const MetaType* valueMetaType = MetaType::find(c.valueType().getName()); // If a type in the collection is Variant, then the handler can vary, so leave it as nullptr. if (keyMetaType != MetaType::get<Variant>()) { keyHandler = handlerManager_.findHandlerWrite(c.begin().key()); } if (valueMetaType != MetaType::get<Variant>()) { valueHandler = handlerManager_.findHandlerWrite(c.begin().value()); } // Create a base node for all the elements in the collection. auto baseNode = node->createEmptyChild(collectionBaseNodeName_, strlen(collectionBaseNodeName_)); // Iterate through all the objects in the collection for (auto iter = c.begin(); iter != c.end(); ++iter) { // Write the key, if it exists Variant key = iter.key(); if (!key.isVoid()) { // Create the key node std::unique_ptr<SerializationNode> keyNode; if (keyHandler.get() == nullptr) { // Variant type, go through the entire system keyNode = baseNode->createChildVariant(keyName_, strlen(keyName_), key); } else { // Non-Variant type, use our handler keyNode = baseNode->createEmptyChild(keyName_, strlen(keyName_)); if (!keyHandler->write(key, keyNode, false)) { return false; } } if (keyNode == nullptr) { return false; } // Write the value Variant value = iter.value(); if (!value.isVoid()) { // Create the value node std::unique_ptr<SerializationNode> valueNode; if (valueHandler.get() == nullptr) { // Variant type, go through the entire system valueNode = keyNode->createChildVariant(valueName_, strlen(valueName_), value); } else { // Non-Variant type, use our handler valueNode = keyNode->createEmptyChild(valueName_, strlen(valueName_)); if (!valueHandler->write(value, valueNode, false)) { return false; } } if (valueNode == nullptr) { return false; } } else { return false; } } else { return false; } } // Write the types and handlers last so that the serialized list can be iterated through intuitively // Container type const char* collectionContainerName = this->getReservedNames().collectionContainerType; auto containerTypeNode = node->createEmptyChild(collectionContainerName, strlen(collectionContainerName)); const char* collectionContainerType = c.impl()->containerType().getName(); containerTypeNode->setType(collectionContainerType, strlen(collectionContainerType)); // Key variant type const char* collectionKeyVName = this->getReservedNames().collectionKeyVariantType; auto keyVTypeNode = node->createEmptyChild(collectionKeyVName, strlen(collectionKeyVName)); const char* collectionKeyVType = c.keyType().getName(); keyVTypeNode->setType(collectionKeyVType, strlen(collectionKeyVType)); // Value variant type const char* collectionValueVName = this->getReservedNames().collectionValueVariantType; auto valueVTypeNode = node->createEmptyChild(collectionValueVName, strlen(collectionValueVName)); const char* collectionValueVType = c.valueType().getName(); valueVTypeNode->setType(collectionValueVType, strlen(collectionValueVType)); // Key internal type const char* collectionKeyIName = this->getReservedNames().collectionKeyInternalType; auto keyITypeNode = node->createEmptyChild(collectionKeyIName, strlen(collectionKeyIName)); const char* collectionKeyIType = keyHandler->getInternalTypeOf(c.begin().key(), node); keyITypeNode->setType(collectionKeyIType, strlen(collectionKeyIType)); // Value internal type const char* collectionValueIName = this->getReservedNames().collectionValueInternalType; auto valueITypeNode = node->createEmptyChild(collectionValueIName, strlen(collectionValueIName)); const char* collectionValueIType = valueHandler->getInternalTypeOf(c.begin().value(), node); valueITypeNode->setType(collectionValueIType, strlen(collectionValueIType)); // Key handler if (keyHandler.get() != nullptr) { const char* collectionKeyHandlerName = this->getReservedNames().collectionKeyHandler; auto keyHandlerNode = node->createEmptyChild(collectionKeyHandlerName, strlen(collectionKeyHandlerName)); const char* collectionKeyHandler = keyHandler->getName(); keyHandlerNode->setValueString(collectionKeyHandler, strlen(collectionKeyHandler)); } // Value handler if (valueHandler.get() != nullptr) { const char* collectionValueHandlerName = this->getReservedNames().collectionValueHandler; auto valueHandlerNode = node->createEmptyChild(collectionValueHandlerName, strlen(collectionValueHandlerName)); const char* collectionValueHandler = valueHandler->getName(); valueHandlerNode->setValueString(collectionValueHandler, strlen(collectionValueHandler)); } return true; }