mirror of
https://github.com/aharabada/glitchy-engine-beef.git
synced 2026-09-05 13:01:52 +00:00
670 lines
18 KiB
Beef
670 lines
18 KiB
Beef
using GlitchyEngine.Core;
|
|
using GlitchyEngine.Scripting;
|
|
using Mono;
|
|
using System;
|
|
using System.Collections;
|
|
using Bon.Integrated;
|
|
using Bon;
|
|
using System.Reflection;
|
|
using GlitchyEngine.Debug;
|
|
using GlitchyEngine.Collections;
|
|
|
|
namespace GlitchyEngine.Serialization;
|
|
|
|
using internal GlitchyEngine.Scripting;
|
|
|
|
[BonTarget]
|
|
class SerializedObject
|
|
{
|
|
[Union]
|
|
public struct FieldData
|
|
{
|
|
public uint8[16] RawData;
|
|
public StringView StringView;
|
|
public ListStringView ListStringView;
|
|
public (StringView FullTypeName, UUID ID) EngineObject;
|
|
public (ListStringView FullTypeName, UUID ID) ListEngineObject;
|
|
|
|
static this()
|
|
{
|
|
// This is important, because we expect 24 Bytes on the C# side
|
|
Compiler.Assert(sizeof(Self) == 24);
|
|
}
|
|
}
|
|
|
|
/// ID used to identify the object represented by this SerializedObject. In case that the represented object is a
|
|
/// Script Instance, the ID is the UUID of the Entity, random otherwise.
|
|
/// Todo: This sucks because we don't know all UUIDs beforehand and might accidentally assign the ID of an Entity to some class
|
|
public UUID Id;
|
|
|
|
public bool IsStatic;
|
|
|
|
public String TypeName ~ delete:append _;
|
|
|
|
public ScriptInstanceSerializer Serializer;
|
|
|
|
private append LessSimpleStringList _betterOwnedStrings = .();
|
|
|
|
//private List<String> _ownedString = new List<String>() ~ DeleteContainerAndItems!(_);
|
|
|
|
public append Dictionary<ListStringView, (SerializationType PrimitiveType, FieldData Data)> Fields = .();
|
|
|
|
[AllowAppend]
|
|
public this(ScriptInstanceSerializer serializer, bool isStatic, StringView? typeName, UUID? id = null)
|
|
{
|
|
//Profiler.ProfileFunction!();
|
|
|
|
String typeNameCopy = append String(typeName.Value);
|
|
|
|
Serializer = serializer;
|
|
|
|
IsStatic = isStatic;
|
|
|
|
if (id == null)
|
|
{
|
|
// Make sure we have no duplicate keys
|
|
repeat
|
|
{
|
|
Id = UUID.Create();
|
|
}
|
|
while (Serializer.ContainsId(Id));
|
|
}
|
|
else
|
|
{
|
|
Id = id.Value;
|
|
}
|
|
|
|
Serializer.AddObject(this);
|
|
|
|
TypeName = typeNameCopy;
|
|
}
|
|
|
|
private void SetDataSimple(SerializationType fieldType, void* rawValue, ref FieldData data)
|
|
{
|
|
Internal.MemCpy(&data.RawData, rawValue, fieldType.GetSize());
|
|
}
|
|
|
|
private void SetRawData<T>(SerializationType fieldType, T rawValue, ref FieldData data)
|
|
{
|
|
#unwarn
|
|
Internal.MemCpy(&data.RawData, &rawValue, fieldType.GetSize());
|
|
}
|
|
|
|
private void AddField(StringView fieldName, SerializationType fieldType, FieldData data)
|
|
{
|
|
ListStringView view = _betterOwnedStrings.Add(fieldName);
|
|
//String nameCopy = new String(fieldName);
|
|
//_ownedString.Add(nameCopy);
|
|
|
|
Fields.Add(view, (fieldType, data));
|
|
}
|
|
|
|
public void AddField(StringView name, SerializationType primitiveType, void* value, StringView fullTypeName)
|
|
{
|
|
Profiler.ProfileFunction!();
|
|
|
|
FieldData data = .();
|
|
|
|
switch (primitiveType)
|
|
{
|
|
case .String, .Enum:
|
|
Profiler.ProfileScope!("String/Enum");
|
|
// If the string is null, we store a nullptr and 0-length
|
|
ListStringView valueView = .();
|
|
|
|
if (value != null)
|
|
{
|
|
StringView stringToCopy = *(StringView*)value;
|
|
//String stringValue = new String(stringToCopy);
|
|
|
|
//_ownedString.Add(stringValue);
|
|
valueView = _betterOwnedStrings.Add(stringToCopy);
|
|
}
|
|
|
|
data.ListStringView = valueView;
|
|
case .EngineObjectReference:
|
|
Profiler.ProfileScope!("EngineObject");
|
|
ListStringView typeNameView = .();
|
|
|
|
if (!fullTypeName.IsEmpty)
|
|
{
|
|
typeNameView = _betterOwnedStrings.Add(fullTypeName);
|
|
//_ownedString.Add(new String(fullTypeName));
|
|
}
|
|
|
|
data.ListEngineObject = (FullTypeName: typeNameView, ID: *(UUID*)value);
|
|
default:
|
|
SetDataSimple(primitiveType, value, ref data);
|
|
}
|
|
|
|
AddField(name, primitiveType, data);
|
|
}
|
|
|
|
/*private void ConvertType(SerializationType fieldType, in FieldData fieldData, SerializationType expectedType, uint8* target)
|
|
{
|
|
#unwarn
|
|
void* rawData = &fieldData.RawData;
|
|
|
|
void SimpleConversion<TActual, TExpected>() where TExpected: operator explicit TActual
|
|
{
|
|
TActual actualValue = *(TActual*)rawData;
|
|
*(TExpected*)target = (TExpected)actualValue;
|
|
}
|
|
|
|
if (fieldType.IsNumber && expectedType.IsNumber)
|
|
{
|
|
Convert.ConvertTo(Variant.Create(fieldType.));
|
|
}
|
|
|
|
switch(fieldType)
|
|
{
|
|
case .Float:
|
|
if (expectedType == .Double)
|
|
SimpleConversion<float, double>();
|
|
case .Double:
|
|
if (expectedType == .Float)
|
|
SimpleConversion<double, float>();
|
|
default:
|
|
Log.EngineLogger.Error($"No field data conversion from {fieldType} to {expectedType}.");
|
|
return;
|
|
}
|
|
}*/
|
|
|
|
public void GetField(StringView fieldName, SerializationType expectedType, uint8* target, out SerializationType actualType)
|
|
{
|
|
// Profiler.ProfileFunction!();
|
|
|
|
actualType = .None;
|
|
|
|
if (!Fields.TryGetValueAlt(fieldName, let field))
|
|
return;
|
|
|
|
actualType = field.PrimitiveType;
|
|
|
|
/*if (expectedType != field.PrimitiveType)
|
|
{
|
|
if (field.PrimitiveType.CanConvertTo(expectedType))
|
|
{
|
|
ConvertType(field.PrimitiveType, field.Data, expectedType, target);
|
|
}
|
|
|
|
return;
|
|
}*/
|
|
|
|
switch (field.PrimitiveType)
|
|
{
|
|
case .String, .Enum:
|
|
*(StringView*)target = (StringView)field.Data.ListStringView;
|
|
case .EngineObjectReference:
|
|
let engineObjectData = field.Data.ListEngineObject;
|
|
|
|
(*(FieldData*)(void*)target).EngineObject.FullTypeName = (StringView)engineObjectData.FullTypeName;
|
|
(*(FieldData*)(void*)target).EngineObject.ID = engineObjectData.ID;
|
|
|
|
/**(char8**)target = engineObjectData.FullTypeName?.CStr();
|
|
*(int*)(target + sizeof(char8*)) = engineObjectData.FullTypeName?.Length ?? 0;
|
|
*(UUID*)(target + sizeof(char8*) + sizeof(int)) = engineObjectData.ID;*/
|
|
|
|
/**(char8**)target = engineObjectData.FullTypeName?.CStr();
|
|
*(int*)(target + sizeof(char8*)) = engineObjectData.FullTypeName?.Length ?? 0;
|
|
*(UUID*)(target + sizeof(char8*) + sizeof(int)) = engineObjectData.ID;*/
|
|
default:
|
|
// Most values can simply be copied, the conversion will be done in C#
|
|
#unwarn
|
|
Internal.MemCpy(target, &field.Data.RawData, sizeof(FieldData));
|
|
}
|
|
}
|
|
|
|
public void Serialize(NewScriptInstance scriptInstance)
|
|
{
|
|
Profiler.ProfileFunction!();
|
|
ScriptEngine.Classes.EntitySerializer.Serialize(scriptInstance, this);
|
|
}
|
|
|
|
public void Deserialize(NewScriptInstance scriptInstance)
|
|
{
|
|
// Profiler.ProfileFunction!();
|
|
ScriptEngine.Classes.EntitySerializer.Deserialize(scriptInstance, this);
|
|
}
|
|
|
|
public void SerializeStaticFields(NewScriptClass scriptClass)
|
|
{
|
|
Profiler.ProfileFunction!();
|
|
ScriptEngine.Classes.EntitySerializer.SerializeStatic(scriptClass, this);
|
|
}
|
|
|
|
public void DeserializeStaticFields(NewScriptClass scriptClass)
|
|
{
|
|
// Profiler.ProfileFunction!();
|
|
ScriptEngine.Classes.EntitySerializer.DeserializeStatic(scriptClass, this);
|
|
}
|
|
|
|
static this
|
|
{
|
|
gBonEnv.typeHandlers.Add(typeof(SerializedObject),
|
|
((.)new => AssetSerialize, null));
|
|
}
|
|
|
|
static T GetFieldDataAs<T>(FieldData fieldData)
|
|
{
|
|
#unwarn
|
|
return *(T*)&fieldData.RawData;
|
|
}
|
|
|
|
static void AssetSerialize(BonWriter writer, ValueView value, BonEnvironment environment, SerializeValueState state)
|
|
{
|
|
// Profiler.ProfileFunction!();
|
|
Log.EngineLogger.Assert(value.type == typeof(Self));
|
|
|
|
SerializedObject object = value.Get<Self>();
|
|
|
|
writer.Type(object.TypeName);
|
|
|
|
using (writer.ObjectBlock())
|
|
{
|
|
Serialize.Value(writer, "ID", object.Id, environment);
|
|
|
|
for (let (fieldName, field) in object.Fields)
|
|
{
|
|
writer.Identifier((StringView)fieldName);
|
|
switch (field.PrimitiveType)
|
|
{
|
|
case .Bool:
|
|
Serialize.Value(writer, GetFieldDataAs<bool>(field.Data), environment);
|
|
case .Char:
|
|
Serialize.Value(writer, GetFieldDataAs<char16>(field.Data), environment);
|
|
case .String:
|
|
if (field.Data.StringView.IsNull)
|
|
{
|
|
writer.Type("string");
|
|
}
|
|
#unwarn
|
|
StringView dataView = (StringView)field.Data.ListStringView;
|
|
Serialize.Value(writer, ValueView(typeof(StringView), &dataView), environment);
|
|
|
|
case .Int8:
|
|
writer.Type("int8");
|
|
Serialize.Value(writer, GetFieldDataAs<int8>(field.Data), environment);
|
|
case .Int16:
|
|
writer.Type("int16");
|
|
Serialize.Value(writer, GetFieldDataAs<int16>(field.Data), environment);
|
|
case .Int32:
|
|
writer.Type("int32");
|
|
Serialize.Value(writer, GetFieldDataAs<int32>(field.Data), environment);
|
|
case .Int64:
|
|
writer.Type("int64");
|
|
Serialize.Value(writer, GetFieldDataAs<int64>(field.Data), environment);
|
|
case .UInt8:
|
|
writer.Type("uint8");
|
|
Serialize.Value(writer, GetFieldDataAs<uint8>(field.Data), environment);
|
|
case .UInt16:
|
|
writer.Type("uint16");
|
|
Serialize.Value(writer, GetFieldDataAs<uint16>(field.Data), environment);
|
|
case .UInt32:
|
|
writer.Type("uint32");
|
|
Serialize.Value(writer, GetFieldDataAs<uint32>(field.Data), environment);
|
|
case .UInt64:
|
|
writer.Type("uint64");
|
|
Serialize.Value(writer, GetFieldDataAs<uint64>(field.Data), environment);
|
|
|
|
case .Float:
|
|
writer.Type("float");
|
|
Serialize.Value(writer, GetFieldDataAs<float>(field.Data), environment);
|
|
case .Double:
|
|
writer.Type("double");
|
|
Serialize.Value(writer, GetFieldDataAs<double>(field.Data), environment);
|
|
case .Decimal:
|
|
writer.Type("decimal");
|
|
Serialize.Value(writer, GetFieldDataAs<MonoDecimal>(field.Data), environment);
|
|
|
|
case .Enum:
|
|
writer.Type("Enum");
|
|
#unwarn
|
|
StringView dataView = (StringView)field.Data.ListStringView;
|
|
Serialize.Value(writer, ValueView(typeof(StringView), &dataView), environment);
|
|
case .EngineObjectReference:
|
|
writer.Type("EngineObject");
|
|
if (field.Data.EngineObject.FullTypeName.IsEmpty)
|
|
writer.Type((StringView)field.Data.ListEngineObject.FullTypeName);
|
|
Serialize.Value(writer, field.Data.EngineObject.ID, environment);
|
|
case .ObjectReference:
|
|
writer.outStr.Append('&');
|
|
GetFieldDataAs<UUID>(field.Data).ToString(writer.outStr);
|
|
writer.EntryEnd();
|
|
default:
|
|
Log.EngineLogger.Warning("Unhandled primitive type");
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
//AssetHandle.[Friend]AssetSerialize(writer, ValueView(typeof(AssetHandle), &handle), environment, state);
|
|
|
|
//writer.String(identifier);
|
|
}
|
|
|
|
private static Result<StringView> NestedIdentifier(BonReader reader)
|
|
{
|
|
let name = ParseNestedName(reader);
|
|
if (name.Length == 0)
|
|
reader.[Friend]Error!("Expected identifier name");
|
|
|
|
Try!(reader.ConsumeEmpty());
|
|
|
|
if (!reader.[Friend]Check('='))
|
|
reader.[Friend]Error!("Expected equals");
|
|
|
|
Try!(reader.ConsumeEmpty());
|
|
|
|
return name;
|
|
}
|
|
|
|
private static StringView ParseNestedName(BonReader reader)
|
|
{
|
|
var nameLen = 0;
|
|
for (; nameLen < reader.inStr.Length; nameLen++)
|
|
{
|
|
let char = reader.inStr[nameLen];
|
|
if (!char.IsLetterOrDigit && char != '_' && char != '.')
|
|
break;
|
|
}
|
|
|
|
let name = reader.inStr.Substring(0, nameLen);
|
|
reader.inStr.RemoveFromStart(nameLen);
|
|
return name;
|
|
}
|
|
|
|
public static Result<SerializedObject> BonDeserialize(BonReader reader, ScriptInstanceSerializer scriptSerializer, int sceneFileVersion, BonEnvironment environment = gBonEnv)
|
|
{
|
|
StringView type = Try!(reader.Type());
|
|
|
|
Try!(reader.ObjectBlock());
|
|
|
|
Try!(Deserialize.Value<UUID>(reader, "ID", let objectId, environment));
|
|
|
|
SerializedObject object = new SerializedObject(scriptSerializer, false, type, objectId);
|
|
|
|
while (reader.ObjectHasMore())
|
|
{
|
|
// TODO: Consume until we hit a comma. In case the current field couldn't be deserialized
|
|
Try!(reader.EntryEnd());
|
|
|
|
FieldData fieldData = .();
|
|
SerializationType fieldType = .None;
|
|
|
|
StringView fieldName = Try!(NestedIdentifier(reader));
|
|
|
|
StringView fieldTypeName = String.Empty;
|
|
|
|
if (reader.IsTyped())
|
|
{
|
|
fieldTypeName = reader.Type();
|
|
}
|
|
|
|
HandleField: do
|
|
{
|
|
if (!fieldTypeName.IsWhiteSpace)
|
|
{
|
|
if (fieldTypeName == "float")
|
|
{
|
|
float floatValue = 0.0f;
|
|
|
|
Deserialize.[Friend]Float!(typeof(float), reader, ValueView(typeof(float), &floatValue));
|
|
fieldType = .Float;
|
|
object.SetRawData(fieldType, floatValue, ref fieldData);
|
|
|
|
break HandleField;
|
|
}
|
|
else if (fieldTypeName == "double")
|
|
{
|
|
double doubleValue = 0.0f;
|
|
|
|
Deserialize.[Friend]Float!(typeof(double), reader, ValueView(typeof(double), &doubleValue));
|
|
fieldType = .Double;
|
|
object.SetRawData(fieldType, doubleValue, ref fieldData);
|
|
|
|
break HandleField;
|
|
}
|
|
else if (fieldTypeName.StartsWith("int"))
|
|
{
|
|
int64 intValue = 0;
|
|
|
|
Deserialize.[Friend]Integer!(typeof(int64), reader, ValueView(typeof(int64), &intValue));
|
|
|
|
if (fieldTypeName.EndsWith("8"))
|
|
{
|
|
fieldType = .Int8;
|
|
object.SetRawData(fieldType, (int8)intValue, ref fieldData);
|
|
}
|
|
else if (fieldTypeName.EndsWith("16"))
|
|
{
|
|
fieldType = .Int16;
|
|
object.SetRawData(fieldType, (int16)intValue, ref fieldData);
|
|
}
|
|
else if (fieldTypeName.EndsWith("32"))
|
|
{
|
|
fieldType = .Int32;
|
|
object.SetRawData(fieldType, (int32)intValue, ref fieldData);
|
|
}
|
|
else if (fieldTypeName.EndsWith("64"))
|
|
{
|
|
fieldType = .Int64;
|
|
object.SetRawData(fieldType, (int64)intValue, ref fieldData);
|
|
}
|
|
else
|
|
{
|
|
Log.ClientLogger.Error($"Unknown integer type {fieldTypeName}");
|
|
}
|
|
|
|
break HandleField;
|
|
}
|
|
else if (fieldTypeName.StartsWith("uint"))
|
|
{
|
|
uint64 intValue = 0;
|
|
|
|
Deserialize.[Friend]Integer!(typeof(uint64), reader, ValueView(typeof(uint64), &intValue));
|
|
|
|
if (fieldTypeName.EndsWith("8"))
|
|
{
|
|
fieldType = .UInt8;
|
|
object.SetRawData(fieldType, (uint8)intValue, ref fieldData);
|
|
}
|
|
else if (fieldTypeName.EndsWith("16"))
|
|
{
|
|
fieldType = .UInt16;
|
|
object.SetRawData(fieldType, (uint16)intValue, ref fieldData);
|
|
}
|
|
else if (fieldTypeName.EndsWith("32"))
|
|
{
|
|
fieldType = .UInt32;
|
|
object.SetRawData(fieldType, (uint32)intValue, ref fieldData);
|
|
}
|
|
else if (fieldTypeName.EndsWith("64"))
|
|
{
|
|
fieldType = .UInt64;
|
|
object.SetRawData(fieldType, (uint64)intValue, ref fieldData);
|
|
}
|
|
else
|
|
{
|
|
Log.ClientLogger.Error($"Unknown integer type {fieldTypeName}");
|
|
}
|
|
|
|
break HandleField;
|
|
}
|
|
else if (fieldTypeName == "decimal")
|
|
{
|
|
StringView numberView = Try!(reader.Floating());
|
|
|
|
if (reader.inStr.StartsWith('m'))
|
|
reader.inStr.RemoveFromStart(1);
|
|
|
|
MonoDecimal decimalValue = Try!(MonoDecimal.Parse(numberView));
|
|
fieldType = .Decimal;
|
|
object.SetRawData(fieldType, decimalValue, ref fieldData);
|
|
|
|
break HandleField;
|
|
}
|
|
else if (fieldTypeName == "Enum")
|
|
{
|
|
Result<void> result = .Ok;
|
|
|
|
Result<void> GetEnum(String outBuffer)
|
|
{
|
|
var outBuffer;
|
|
Deserialize.String!(reader, ref outBuffer, environment);
|
|
return .Ok;
|
|
}
|
|
|
|
fieldData.ListStringView = object._betterOwnedStrings.Add(scope [&](s) =>
|
|
{
|
|
result = GetEnum(s);
|
|
});
|
|
|
|
/*String enumValue = new .();
|
|
Deserialize.String!(reader, ref enumValue, environment);*/
|
|
|
|
//object._ownedString.Add(enumValue);
|
|
//fieldData.ListStringView = object._betterOwnedStrings.Add(enumValue);
|
|
//fieldData.StringView = enumValue;
|
|
fieldType = .Enum;
|
|
|
|
Try!(result);
|
|
|
|
break HandleField;
|
|
}
|
|
else if (fieldTypeName == "EngineObject")
|
|
{
|
|
ListStringView entityTypeName = .();
|
|
|
|
if (reader.IsTyped())
|
|
{
|
|
StringView entityTypeNameView = Try!(reader.Type());
|
|
|
|
//entityTypeName = new String(entityTypeNameView);
|
|
|
|
//object._ownedString.Add(entityTypeName);
|
|
|
|
entityTypeName = object._betterOwnedStrings.Add(entityTypeNameView);
|
|
}
|
|
|
|
// Object Reference
|
|
uint64 id = 0;
|
|
|
|
Deserialize.[Friend]Integer!(typeof(uint64), reader, ValueView(typeof(uint64), &id));
|
|
|
|
UUID reference = UUID(id);
|
|
fieldType = .EngineObjectReference;
|
|
fieldData.ListEngineObject = (FullTypeName: entityTypeName, ID: reference);
|
|
|
|
break HandleField;
|
|
}
|
|
}
|
|
|
|
if (Deserialize.IsBool(reader))
|
|
{
|
|
bool boolValue = Try!(reader.Bool());
|
|
fieldType = .Bool;
|
|
object.SetDataSimple(fieldType, &boolValue, ref fieldData);
|
|
}
|
|
else if (reader.[Friend]Check('\'', false))
|
|
{
|
|
char32 c = Try!(reader.Char());
|
|
|
|
fieldType = .Char;
|
|
object.SetDataSimple(fieldType, &c, ref fieldData);
|
|
}
|
|
else if (reader.[Friend]Check('"', false) || fieldTypeName == "string")
|
|
{
|
|
if (reader.inStr.StartsWith("null"))
|
|
{
|
|
fieldData.StringView = null;
|
|
fieldType = .String;
|
|
reader.inStr.RemoveFromStart(4);
|
|
}
|
|
else
|
|
{
|
|
Result<void> result = .Ok;
|
|
|
|
Result<void> GetStringValue(String outBuffer)
|
|
{
|
|
var outBuffer;
|
|
Deserialize.String!(reader, ref outBuffer, environment);
|
|
return .Ok;
|
|
}
|
|
|
|
fieldData.ListStringView = object._betterOwnedStrings.Add(scope [&](s) =>
|
|
{
|
|
result = GetStringValue(s);
|
|
});
|
|
|
|
fieldType = .String;
|
|
|
|
Try!(result);
|
|
|
|
/*String target = new .();
|
|
Deserialize.String!(reader, ref target, environment);
|
|
|
|
object._ownedString.Add(target);
|
|
fieldData.StringView = target;
|
|
fieldType = .String;*/
|
|
}
|
|
}
|
|
// else if (Deserialize.IsNumber(reader, let numberType))
|
|
// {
|
|
// if (numberType == .Double)
|
|
// {
|
|
// double double = Try!(Deserialize.ParseFloat<double>());
|
|
// fieldType = .Double;
|
|
// object.SetDataSimple(fieldType, &reference, ref fieldData);
|
|
// }
|
|
// else if (numberType == .Float)
|
|
// {
|
|
// float double = Try!(Deserialize.ParseFloat<float>());
|
|
// fieldType = .Float;
|
|
// object.SetDataSimple(fieldType, &reference, ref fieldData);
|
|
// }
|
|
// else if (numberType == .Integer)
|
|
// {
|
|
// bool isNegative = false;
|
|
|
|
// if (reader.inStr.StartsWith('-'))
|
|
// {
|
|
// isNegative = true;
|
|
// }
|
|
|
|
// float double = Try!(Deserialize.ParseInt<u>());
|
|
// fieldType = .Float;
|
|
// object.SetDataSimple(fieldType, &reference, ref fieldData);
|
|
// }
|
|
// }
|
|
else if (reader.IsReference())
|
|
{
|
|
// Object Reference
|
|
StringView referenceView = Try!(reader.Reference());
|
|
|
|
let referenceResult = uint64.Parse(referenceView);
|
|
|
|
if (referenceResult case .Ok(let referenceInt))
|
|
{
|
|
UUID reference = UUID(referenceInt);
|
|
fieldType = .ObjectReference;
|
|
object.SetRawData(fieldType, reference, ref fieldData);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (fieldType != .None)
|
|
{
|
|
object.AddField(fieldName, fieldType, fieldData);
|
|
}
|
|
|
|
Try!(reader.ConsumeEmpty());
|
|
}
|
|
|
|
Try!(reader.ObjectBlockEnd());
|
|
|
|
return .Ok(object);
|
|
}
|
|
}
|