Skip to content

Commit

Permalink
Move enum parse impl
Browse files Browse the repository at this point in the history
Signed-off-by: Thomas Farr <tsfarr@amazon.com>
  • Loading branch information
Xtansia committed Sep 20, 2024
1 parent fc59392 commit 85c6db7
Show file tree
Hide file tree
Showing 3 changed files with 35 additions and 98 deletions.
38 changes: 5 additions & 33 deletions src/OpenSearch.Net/Api/Enums.cs
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,6 @@ 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 All @@ -77,44 +76,17 @@ private static Func<Enum, string> GetEnumStringResolver(Type type)
var dictionary = new Dictionary<Enum, string>(values.Length);
for (var index = 0; index < values.Length; index++)
{
var value = values.GetValue(index);
var value = (Enum) 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((Enum)value, stringValue);
var attr = info.GetCustomAttribute<EnumMemberAttribute>(false);
var stringValue = attr != null ? attr.Value : Enum.GetName(type, value);
dictionary.Add(value, stringValue);
}

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

internal 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)Enum.ToObject(type, s.ToLowerInvariant().Split(',').Aggregate(0, (acc, value) => acc | Convert.ToInt32(dictionary[value])))
: s => dictionary[s.ToLowerInvariant()];
}
}
}
33 changes: 30 additions & 3 deletions tests/Tests.YamlRunner/DoMapper.fs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ open System.Collections.ObjectModel
open System.Globalization
open System.Linq
open System.Linq.Expressions
open System.Runtime.Serialization
open System.Threading.Tasks
open Tests.YamlRunner.Models
open OpenSearch.Net
Expand Down Expand Up @@ -89,7 +90,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 -> typeof<KnownEnums>.GetMethod("Parse").MakeGenericMethod(t).Invoke(null, [|v|])
| t when t.IsEnum -> this.ArgEnum(this.ArgString v, t)
| t -> failwithf $"unable to convert argument to type %s{t.FullName}"

member this.ArgString (v:Object): string =
Expand All @@ -101,7 +102,7 @@ type FastApiInvoke(instance: Object, restName:string, pathParams:KeyedCollection
| :? double as i -> i.ToString(CultureInfo.InvariantCulture)
| :? int64 as i -> i.ToString(CultureInfo.InvariantCulture)
| :? Boolean as b -> if b then "false" else "true"
| e -> failwithf "unknown type %s " (e.GetType().Name)
| e -> failwithf $"unknown type %s{e.GetType().Name}"

match v with
| :? List<Object> as a ->
Expand All @@ -111,7 +112,33 @@ type FastApiInvoke(instance: Object, restName:string, pathParams:KeyedCollection
| [] -> "_all"
| _ -> String.Join(',', values)
| e -> toString e


member this.ArgEnum (v:String, t:Type): Enum =
let values = Enum.GetValues(t)

let lookup =
values
|> Seq.cast<Enum>
|> Seq.map (fun e ->
let field = t.GetField(e.ToString())
let attr = field.GetCustomAttribute<EnumMemberAttribute>()
let stringValue = if attr <> null then attr.Value else Enum.GetName(t, e)
(stringValue.ToLowerInvariant(), e)
)
|> Map.ofSeq

let result =
v.ToLowerInvariant().Split(',')
|> Seq.map (_.Trim())
|> Seq.map (fun s ->
match lookup.TryGetValue(s) with
| true, e -> e
| false, _ -> failwithf $"unable to find enum value %s{s}"
)
|> Seq.map Convert.ToInt32
|> Seq.reduce (fun acc e -> acc ||| e)

Enum.ToObject(t, result) :?> Enum

member this.CanInvoke (o:YamlMap) =
let operationKeys =
Expand Down
62 changes: 0 additions & 62 deletions tests/Tests/ClientConcepts/Enums/EnumParsingTests.cs

This file was deleted.

0 comments on commit 85c6db7

Please sign in to comment.