Bofa/src/Serialization/BofaSerializeAttribute.bf

135 lines
No EOL
3.2 KiB
Beef

namespace Bofa.Serialization;
using System;
using System.Reflection;
using Bofa;
[AttributeUsage(.Struct | .Class)]
struct BofaSerializeAttribute : Attribute, IOnTypeInit
{
private bool Strict;
public this(bool pStrict = false)
{
Strict = pStrict;
}
[Comptime]
public void OnTypeInit(Type type, Self* prev)
{
String serializeString = scope .("public bool Serialize(Bofa b)\n{\n");
String deserializeString = scope .("public bool Deserialize(Bofa b)\n{\n");
serializeString.Append("""
b.Type = .Object;
b.Value.Object = new .();
b.Typename = "Object";
Bofa toAdd;
""");
deserializeString.Append("""
if(b.Type != .Object)
return false;
""");
var fields = type.GetFields();
for(var f in fields)
{
if(!f.IsPublic && !f.HasCustomAttribute<BofaIncludeAttribute>())
continue;
bool hasIFace = false;
for(var i in f.FieldType.Interfaces)
if(i == typeof(IBofaParseable))
hasIFace = true;
//Hardcoded stuff
if(f.FieldType == typeof(int))
hasIFace = true;
else if(f.FieldType == typeof(int8))
hasIFace = true;
else if(f.FieldType == typeof(int16))
hasIFace = true;
else if(f.FieldType == typeof(int32))
hasIFace = true;
else if(f.FieldType == typeof(int64))
hasIFace = true;
else if(f.FieldType == typeof(uint))
hasIFace = true;
else if(f.FieldType == typeof(uint8))
hasIFace = true;
else if(f.FieldType == typeof(uint16))
hasIFace = true;
else if(f.FieldType == typeof(uint32))
hasIFace = true;
else if(f.FieldType == typeof(uint64))
hasIFace = true;
else if(f.FieldType == typeof(char8))
hasIFace = true;
else if(f.FieldType == typeof(char16))
hasIFace = true;
else if(f.FieldType == typeof(char32))
hasIFace = true;
else if(f.FieldType == typeof(float))
hasIFace = true;
else if(f.FieldType == typeof(double))
hasIFace = true;
else if(f.FieldType == typeof(System.Security.Cryptography.SHA256Hash))
hasIFace = true;
if(!hasIFace)
continue;
StringView name;
name = f.Name;
if(f.HasCustomAttribute<BofaIncludeAttribute>() && f.GetCustomAttribute<BofaIncludeAttribute>() case .Ok(let attr))
name = attr.Name;
var required = f.HasCustomAttribute<BofaRequiredAttribute>() || Strict;
serializeString.Append(scope $"""
toAdd = new .();
toAdd.Name = "{name}";
if(!{f.Name}.Serialize(toAdd))
\{
delete toAdd;
{required ? "return false;" : ""}
\}
else
b.Value.Object.Add("{name}", toAdd);
""");
if(required)
{
deserializeString.Append((scope $"""
if(!b.Value.Object.ContainsKey("{name}"))
return false;
if(!{f.Name}.Deserialize(b.Value.Object["{name}"]))
return false;
"""));
}
else
{
deserializeString.Append(scope $"""
if(b.Value.Object.ContainsKey("{name}"))
{f.Name}.Deserialize(b.Value.Object["{name}"]);
""");
}
}
serializeString.Append("\n\treturn true;\n}\n");
deserializeString.Append("\n\treturn true;\n}\n");
Compiler.EmitTypeBody(type, serializeString);
Compiler.EmitTypeBody(type, deserializeString);
Compiler.EmitAddInterface(type, typeof(IBofaParseable));
}
}