using System.Reflection; using System.Collections; namespace System { struct Enum { [NoShow(true)] public static int GetCount(Type type) { int count = 0; for (var field in type.GetFields()) { if (field.IsEnumCase) count++; } return count; } [NoShow(true)] [Comptime(ConstEval=true)] public static int GetCount() where T : Enum { return GetCount(typeof(T)); } [NoShow(true)] public static int64 GetMinValue(Type type) { int64? minValue = null; for (var data in GetValues(type)) { if (minValue == null) minValue = data; else minValue = Math.Min(minValue.Value, data); } return minValue.ValueOrDefault; } [NoShow(true)] [Comptime(ConstEval=true)] public static var GetMinValue() where T : Enum { Compiler.SetReturnType(typeof(T)); return GetMinValue(typeof(T)); } [NoShow(true)] public static int64 GetMaxValue(Type type) { int64? maxValue = null; for (var data in GetValues(type)) { if (maxValue == null) maxValue = data; else maxValue = Math.Max(maxValue.Value, data); } return maxValue ?? -1; } [NoShow(true)] [Comptime(ConstEval=true)] public static var GetMaxValue() where T : Enum { Compiler.SetReturnType(typeof(T)); return GetMaxValue(typeof(T)); } [NoShow(true)] public static void EnumToString(Type type, String strBuffer, int64 iVal) { for (var (name, data) in GetEnumerator(type)) { if (data == iVal) { strBuffer.Append(name); return; } } iVal.ToString(strBuffer); } [NoShow(true)] public static Result Parse(Type type, StringView str, bool ignoreCase = false) { for (var (name, data) in GetEnumerator(type)) { if (str.Equals(name, ignoreCase)) return .Ok(data); if (int64.Parse(str) case .Ok(let val) && val == data) return .Ok(data); } return .Err; } [NoShow(true)] public static Result Parse(StringView str, bool ignoreCase = false) where T : enum { return EnumParser.Parse(str, ignoreCase); } [NoShow(true)] public static bool IsDefined(Type type, int64 value) { for (var data in GetValues(type)) { if (data == value) return true; } return false; } [NoShow(true)] public static bool IsDefined(T value) where T : Enum where T : enum { for (var data in GetValues()) { if (data == (.)value) return true; } return false; } [NoShow(true)] public static EnumEnumerator GetEnumerator(Type type) { return .(type); } [NoShow(true)] public static EnumEnumerator GetEnumerator() where TEnum : enum { return .(); } [NoShow(true)] public static EnumValuesEnumerator GetValues(Type type) { return .(type); } [NoShow(true)] public static EnumValuesEnumerator GetValues() where TEnum : enum { return .(); } [NoShow(true)] public static EnumNamesEnumerator GetNames(Type type) { return .(type); } [NoShow(true)] public static EnumNamesEnumerator GetNames() where TEnum : enum { return .(); } [NoShow(true)] private struct EnumFieldsEnumerator { TypeInstance mTypeInstance; int32 mIdx; public this(Type type) { mTypeInstance = type as TypeInstance; mIdx = -1; } public void Reset() mut { mIdx = -1; } public void Dispose() { } public bool MoveNext() mut { if (mTypeInstance == null) return false; TypeInstance.FieldData* fieldData = null; repeat { mIdx++; if (mIdx == mTypeInstance.[Friend]mFieldDataCount) return false; fieldData = &mTypeInstance.[Friend]mFieldDataPtr[mIdx]; } while (!fieldData.mFlags.HasFlag(.EnumCase)); return true; } public FieldInfo Current { get { var fieldData = &mTypeInstance.[Friend]mFieldDataPtr[mIdx]; return FieldInfo(mTypeInstance, fieldData); } } public int32 Index { get { return mIdx; } } public Result GetNext() mut { if (!MoveNext()) return .Err; return Current; } } [NoShow(true)] public struct EnumEnumerator : EnumFieldsEnumerator, IEnumerator<(StringView name, int64 value)> { public this(Type type) : base(type) { } public new (StringView name, int64 value) Current { get { return ((.)base.Current.[Friend]mFieldData.[Friend]mName, *(int64*)&base.Current.[Friend]mFieldData.[Friend]mData); } } public new Result<(StringView name, int64 value)> GetNext() mut { if (!MoveNext()) return .Err; return Current; } } [NoShow(true)] public struct EnumEnumerator : EnumFieldsEnumerator, IEnumerator<(StringView name, TEnum value)> where TEnum : enum { public this() : base(typeof(TEnum)) { } public new (StringView name, TEnum value) Current { get { return ((.)base.Current.[Friend]mFieldData.[Friend]mName, (.)*(int64*)&base.Current.[Friend]mFieldData.[Friend]mData); } } public new Result<(StringView name, TEnum value)> GetNext() mut { if (!MoveNext()) return .Err; return Current; } } [NoShow(true)] public struct EnumValuesEnumerator : EnumFieldsEnumerator, IEnumerator { public this(Type type) : base(type) { } public new int64 Current { get { return *(int64*)&base.Current.[Friend]mFieldData.[Friend]mData; } } public new Result GetNext() mut { if (!MoveNext()) return .Err; return Current; } } [NoShow(true)] public struct EnumValuesEnumerator : EnumFieldsEnumerator, IEnumerator where TEnum : enum { public this() : base(typeof(TEnum)) { } public new TEnum Current { get { return (.)*(int64*)&base.Current.[Friend]mFieldData.[Friend]mData; } } public new Result GetNext() mut { if (!MoveNext()) return .Err; return Current; } } [NoShow(true)] public struct EnumNamesEnumerator : EnumFieldsEnumerator, IEnumerator { public this(Type type) : base(type) { } public new StringView Current { get { return (.)base.Current.[Friend]mFieldData.[Friend]mName; } } public new Result GetNext() mut { if (!MoveNext()) return .Err; return Current; } } [NoShow(true)] public struct EnumNamesEnumerator : EnumFieldsEnumerator, IEnumerator where TEnum : enum { public this() : base(typeof(TEnum)) { } public new StringView Current { get { return (.)base.Current.[Friend]mFieldData.[Friend]mName; } } public new Result GetNext() mut { if (!MoveNext()) return .Err; return Current; } } } class EnumParser { [OnCompile(.TypeInit), Comptime] public static void OnTypeInit() { String code = scope .(); code.Append("public static Result 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 EnumFields(StringView str) { var str; str.Trim(); if (!str.EndsWith(')')) return .Err; str.RemoveFromEnd(1); return str.Split(','); } static Result ParseValue(ref StringSplitEnumerator itr, ref TValue value) { return .Err; } static Result ParseValue(ref StringSplitEnumerator itr, ref TValue value) where TValue : IParseable { var str = Try!(itr.GetNext()); str.Trim(); value = Try!(TValue.Parse(str)); return .Ok; } } }