1//************************************ bs::framework - Copyright 2018 Marko Pintera **************************************//
2//*********** Licensed under the MIT license. See LICENSE.md for full terms. This notice is not to be removed. ***********//
3#include "Serialization/BsBinaryCloner.h"
4#include "Reflection/BsIReflectable.h"
5#include "Reflection/BsRTTIType.h"
6#include "Reflection/BsRTTIField.h"
7#include "Reflection/BsRTTIPlainField.h"
8#include "Reflection/BsRTTIReflectableField.h"
9#include "Reflection/BsRTTIReflectablePtrField.h"
10#include "Reflection/BsRTTIManagedDataBlockField.h"
11#include "Serialization/BsMemorySerializer.h"
12
13namespace bs
14{
15 SPtr<IReflectable> BinaryCloner::clone(IReflectable* object, bool shallow)
16 {
17 if (object == nullptr)
18 return nullptr;
19
20 ObjectReferenceData referenceData;
21 if (shallow)
22 {
23 FrameAlloc& alloc = gFrameAlloc();
24
25 alloc.markFrame();
26 gatherReferences(object, alloc, referenceData);
27 alloc.clear();
28 }
29
30 std::function<void*(UINT32)> allocator = &MemoryAllocator<GenAlloc>::allocate;
31
32 MemorySerializer ms;
33 UINT32 dataSize = 0;
34 UINT8* data = ms.encode(object, dataSize, allocator, shallow);
35 SPtr<IReflectable> clonedObj = ms.decode(data, dataSize);
36
37 if (shallow)
38 {
39 FrameAlloc& alloc = gFrameAlloc();
40
41 alloc.markFrame();
42 restoreReferences(clonedObj.get(), alloc, referenceData);
43 alloc.clear();
44 }
45
46 bs_free(data);
47 return clonedObj;
48 }
49
50 void BinaryCloner::gatherReferences(IReflectable* object, FrameAlloc& alloc, ObjectReferenceData& referenceData)
51 {
52 if (object == nullptr)
53 return;
54
55 RTTITypeBase* rtti = object->getRTTI();
56 Stack<RTTITypeBase*> rttiInstances;
57 while (rtti != nullptr)
58 {
59 RTTITypeBase* rttiInstance = rtti->_clone(alloc);
60
61 rttiInstance->onSerializationStarted(object, nullptr);
62 SubObjectReferenceData* subObjectData = nullptr;
63
64 UINT32 numFields = rtti->getNumFields();
65 for (UINT32 i = 0; i < numFields; i++)
66 {
67 RTTIField* field = rtti->getField(i);
68 FieldId fieldId;
69 fieldId.field = field;
70 fieldId.arrayIdx = -1;
71
72 if (field->isArray())
73 {
74 const UINT32 numElements = field->getArraySize(rttiInstance, object);
75
76 for (UINT32 j = 0; j < numElements; j++)
77 {
78 fieldId.arrayIdx = j;
79
80 if (field->mType == SerializableFT_ReflectablePtr)
81 {
82 auto* curField = static_cast<RTTIReflectablePtrFieldBase*>(field);
83 SPtr<IReflectable> childObj = curField->getArrayValue(rttiInstance, object, j);
84
85 if (childObj != nullptr)
86 {
87 if (subObjectData == nullptr)
88 {
89 referenceData.subObjectData.push_back(SubObjectReferenceData());
90 subObjectData = &referenceData.subObjectData[referenceData.subObjectData.size() - 1];
91 subObjectData->rtti = rtti;
92 }
93
94 subObjectData->references.push_back(ObjectReference());
95 ObjectReference& reference = subObjectData->references.back();
96 reference.fieldId = fieldId;
97 reference.object = childObj;
98 }
99 }
100 else if (field->mType == SerializableFT_Reflectable)
101 {
102 auto* curField = static_cast<RTTIReflectableFieldBase*>(field);
103 IReflectable* childObj = &curField->getArrayValue(rttiInstance, object, j);
104
105 if (subObjectData == nullptr)
106 {
107 referenceData.subObjectData.push_back(SubObjectReferenceData());
108 subObjectData = &referenceData.subObjectData[referenceData.subObjectData.size() - 1];
109 subObjectData->rtti = rtti;
110 }
111
112 subObjectData->children.push_back(ObjectReferenceData());
113 ObjectReferenceData& childData = subObjectData->children.back();
114 childData.fieldId = fieldId;
115
116 gatherReferences(childObj, alloc, childData);
117 }
118 }
119 }
120 else
121 {
122 if (field->mType == SerializableFT_ReflectablePtr)
123 {
124 auto* curField = static_cast<RTTIReflectablePtrFieldBase*>(field);
125 SPtr<IReflectable> childObj = curField->getValue(rttiInstance, object);
126
127 if (childObj != nullptr)
128 {
129 if (subObjectData == nullptr)
130 {
131 referenceData.subObjectData.push_back(SubObjectReferenceData());
132 subObjectData = &referenceData.subObjectData[referenceData.subObjectData.size() - 1];
133 subObjectData->rtti = rtti;
134 }
135
136 subObjectData->references.push_back(ObjectReference());
137 ObjectReference& reference = subObjectData->references.back();
138 reference.fieldId = fieldId;
139 reference.object = childObj;
140 }
141 }
142 else if (field->mType == SerializableFT_Reflectable)
143 {
144 auto* curField = static_cast<RTTIReflectableFieldBase*>(field);
145 IReflectable* childObj = &curField->getValue(rttiInstance, object);
146
147 if (subObjectData == nullptr)
148 {
149 referenceData.subObjectData.push_back(SubObjectReferenceData());
150 subObjectData = &referenceData.subObjectData[referenceData.subObjectData.size() - 1];
151 subObjectData->rtti = rtti;
152 }
153
154 subObjectData->children.push_back(ObjectReferenceData());
155 ObjectReferenceData& childData = subObjectData->children.back();
156 childData.fieldId = fieldId;
157
158 gatherReferences(childObj, alloc, childData);
159 }
160 }
161 }
162
163 rttiInstances.push(rttiInstance);
164 rtti = rtti->getBaseClass();
165 }
166
167 while (!rttiInstances.empty())
168 {
169 RTTITypeBase* rttiInstance = rttiInstances.top();
170 rttiInstances.pop();
171
172 rttiInstance->onSerializationEnded(object, nullptr);
173 alloc.destruct(rttiInstance);
174 }
175 }
176
177 void BinaryCloner::restoreReferences(IReflectable* object, FrameAlloc& alloc, const ObjectReferenceData& referenceData)
178 {
179 for(auto iter = referenceData.subObjectData.rbegin(); iter != referenceData.subObjectData.rend(); ++iter)
180 {
181 const SubObjectReferenceData& subObject = *iter;
182
183 if (!subObject.references.empty())
184 {
185 RTTITypeBase* rttiInstance = subObject.rtti->_clone(alloc);
186 rttiInstance->onDeserializationStarted(object, nullptr);
187
188 for (auto& reference : subObject.references)
189 {
190 auto* curField = static_cast<RTTIReflectablePtrFieldBase*>(reference.fieldId.field);
191
192 if (curField->isArray())
193 curField->setArrayValue(rttiInstance, object, reference.fieldId.arrayIdx, reference.object);
194 else
195 curField->setValue(rttiInstance, object, reference.object);
196 }
197
198 rttiInstance->onDeserializationEnded(object, nullptr);
199 alloc.destruct(rttiInstance);
200 }
201 }
202
203 for (auto& subObject : referenceData.subObjectData)
204 {
205 if (!subObject.children.empty())
206 {
207 RTTITypeBase* rttiInstance = subObject.rtti->_clone(alloc);
208 rttiInstance->onSerializationStarted(object, nullptr);
209
210 for (auto& childObjectData : subObject.children)
211 {
212 auto* curField = static_cast<RTTIReflectableFieldBase*>(childObjectData.fieldId.field);
213
214 IReflectable* childObj = nullptr;
215 if (curField->isArray())
216 childObj = &curField->getArrayValue(rttiInstance, object, childObjectData.fieldId.arrayIdx);
217 else
218 childObj = &curField->getValue(rttiInstance, object);
219
220 restoreReferences(childObj, alloc, childObjectData);
221 }
222
223 rttiInstance->onSerializationEnded(object, nullptr);
224 alloc.destruct(rttiInstance);
225 }
226 }
227 }
228}