Skip to content

Commit

Permalink
Implement enum parsing
Browse files Browse the repository at this point in the history
Signed-off-by: Thomas Farr <[email protected]>
  • Loading branch information
Xtansia committed Sep 20, 2024
1 parent 4a39935 commit 04c7c83
Show file tree
Hide file tree
Showing 2 changed files with 32 additions and 4 deletions.
34 changes: 31 additions & 3 deletions src/OpenSearch.Net/Api/Enums.cs
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ namespace OpenSearch.Net
public static partial class KnownEnums
{
private static readonly ConcurrentDictionary<Type, Func<Enum, string>> EnumStringResolvers = new();
private static readonly ConcurrentDictionary<Type, Func<string, Enum>> EnumStringParsers = new();

static KnownEnums() => RegisterEnumStringResolvers();

Expand Down Expand Up @@ -84,9 +85,36 @@ private static Func<Enum, string> GetEnumStringResolver(Type type)
}

var isFlag = type.GetCustomAttributes(typeof(FlagsAttribute), false).Length > 0;
return e => !isFlag
? dictionary[e]
: string.Join(",", dictionary.Where(kv => e.HasFlag(kv.Key)).Select(kv => kv.Value));
return isFlag
? e => string.Join(",", dictionary.Where(kv => e.HasFlag(kv.Key)).Select(kv => kv.Value))
: e => dictionary[e];
}

public static TEnum Parse<TEnum>(string value)
where TEnum : struct, Enum
{
var parser = EnumStringParsers.GetOrAdd(typeof(TEnum), GetEnumStringParser);
return (TEnum) parser(value);
}

private static Func<string, Enum> GetEnumStringParser(Type type)
{
var values = Enum.GetValues(type);
var dictionary = new Dictionary<string, Enum>(values.Length);
for (var index = 0; index < values.Length; index++)
{
var value = values.GetValue(index);
var info = type.GetField(value.ToString());
var da = (EnumMemberAttribute[])info.GetCustomAttributes(typeof(EnumMemberAttribute), false);
var stringValue = da.Length > 0 ? da[0].Value : Enum.GetName(type, value)!;
dictionary.Add(stringValue.ToLowerInvariant(), (Enum)value);
}

var isFlag = type.GetCustomAttributes(typeof(FlagsAttribute), false).Length > 0;

return isFlag
? s => (Enum) Convert.ChangeType(s.ToLowerInvariant().Split(',').Aggregate(0ul, (acc, value) => acc | Convert.ToUInt64(dictionary[value])), type)
: s => dictionary[s.ToLowerInvariant()];
}
}
}
2 changes: 1 addition & 1 deletion tests/Tests.YamlRunner/DoMapper.fs
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ type FastApiInvoke(instance: Object, restName:string, pathParams:KeyedCollection
let underlyingType = Nullable.GetUnderlyingType(t)
if v = null then null
else this.ArgConvert(v, underlyingType)
| t when t.IsEnum -> Enum.Parse(t, this.ArgString v, true)
| t when t.IsEnum -> typeof<KnownEnums>.GetMethod("Parse").MakeGenericMethod(t).Invoke(null, [|v|])
| t -> failwithf $"unable to convert argument to type %s{t.FullName}"

member this.ArgString (v:Object): string =
Expand Down

0 comments on commit 04c7c83

Please sign in to comment.