1
0
Fork 0
mirror of https://github.com/beefytech/Beef.git synced 2025-06-10 12:32:20 +02:00

Added EnumParser<T> that can parse enums with payloads

This commit is contained in:
Brian Fiete 2024-02-27 10:54:07 -05:00
parent 9ef776a914
commit 47c9305253

View file

@ -99,15 +99,7 @@ namespace System
[NoShow(true)]
public static Result<T> Parse<T>(StringView str, bool ignoreCase = false) where T : enum
{
for (var (name, data) in GetEnumerator<T>())
{
if (str.Equals(name, ignoreCase))
return .Ok(data);
if (int64.Parse(str) case .Ok(let val) && val == (.)data)
return .Ok(data);
}
return .Err;
return EnumParser<T>.Parse(str, ignoreCase);
}
[NoShow(true)]
@ -380,4 +372,110 @@ namespace System
}
}
}
class EnumParser<T>
{
[OnCompile(.TypeInit), Comptime]
public static void OnTypeInit()
{
String code = scope .();
code.Append("public static Result<T> Parse(StringView str, bool ignoreCase = false)\n");
code.Append("{\n");
Type dscrType = typeof(int);
int dscrOffset = 0;
for (var fieldInfo in typeof(T).GetFields())
{
if (fieldInfo.Name == "$discriminator")
{
dscrOffset = fieldInfo.MemberOffset;
dscrType = fieldInfo.FieldType;
}
}
bool hadPayload = false;
for (var fieldInfo in typeof(T).GetFields())
{
if (var fieldTypeInst = fieldInfo.FieldType as TypeInstance)
{
if ((fieldTypeInst.IsTuple) && (fieldTypeInst.FieldCount > 0))
{
code.Append("\tT result = default;\n");
hadPayload = true;
break;
}
}
}
int caseIdx = 0;
for (var fieldInfo in typeof(T).GetFields())
{
if (!fieldInfo.IsEnumCase)
continue;
if (var fieldTypeInst = fieldInfo.FieldType as TypeInstance)
{
bool hasPayload = (fieldTypeInst.IsTuple) && (fieldTypeInst.FieldCount > 0);
if (caseIdx == 0)
code.Append("\t");
else
code.Append("\telse ");
if (!hasPayload)
{
code.AppendF($"if (str.Equals(\"{fieldInfo.Name}\", ignoreCase))\n\t\treturn .Ok(.{fieldInfo.Name});\n");
}
else
{
code.AppendF($"if (str.StartsWith(\"{fieldInfo.Name}(\", ignoreCase ? .OrdinalIgnoreCase : .Ordinal))\n\t{{\n");
code.AppendF($"\t\t*({dscrType}*)((uint8*)&result + {dscrOffset}) = {fieldInfo.MemberOffset};\n");
code.AppendF($"\t\tvar itr = Try!(EnumFields(str.Substring({fieldInfo.Name.Length+1})));\n");
for (var tupField in fieldTypeInst.GetFields())
code.AppendF($"\t\tTry!(ParseValue(ref itr, ref *({tupField.FieldType}*)((uint8*)&result + {tupField.MemberOffset})));\n");
code.Append("\t}\n");
}
}
caseIdx++;
}
if (caseIdx == 0)
{
code.Append("\treturn .Err;\n");
}
else
{
code.Append("\telse\n\t\treturn .Err;\n");
if (hadPayload)
code.Append("\treturn result;\n");
}
code.Append("}\n");
Compiler.EmitTypeBody(typeof(Self), code);
}
static Result<StringSplitEnumerator> EnumFields(StringView str)
{
var str;
str.Trim();
if (!str.EndsWith(')'))
return .Err;
str.RemoveFromEnd(1);
return str.Split(',');
}
static Result<void> ParseValue<TValue>(ref StringSplitEnumerator itr, ref TValue value)
{
return .Err;
}
static Result<void> ParseValue<TValue>(ref StringSplitEnumerator itr, ref TValue value) where TValue : IParseable<TValue>
{
var str = Try!(itr.GetNext());
str.Trim();
value = Try!(TValue.Parse(str));
return .Ok;
}
}
}