Skip to content

Instantly share code, notes, and snippets.

@sitepodmatt
Last active July 25, 2019 15:09
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sitepodmatt/99480607962e2bf9de092e84890dd693 to your computer and use it in GitHub Desktop.
Save sitepodmatt/99480607962e2bf9de092e84890dd693 to your computer and use it in GitHub Desktop.
fsharp union codec
public static class FSharpUnionCodecBuilder
{
public delegate T Decoder<T>(byte[] bytes, string subType);
public delegate byte[] Encoder<T>(T input);
public static Tuple<Decoder<T>,Encoder<T>> Build<T>(T unionType) where T : class
{
var unionCaseFields = FSharpType.GetUnionCases(typeof(T), BindingFlags.Public)
.ToDictionary(uc => $"{uc.DeclaringType.Name}:{uc.Name}",
uc => new Tuple<UnionCaseInfo, Type>(uc,
uc.GetFields().FirstOrDefault()?.DeclaringType
?? throw new ArgumentException("Must have union case argument")));
var decoder = (Decoder<T>) ((byte[] bytes, string subTypeName) => {
var jsonText = System.Text.Encoding.UTF8.GetString(bytes);
var (targetSubType, fieldType) =
unionCaseFields[subTypeName] ?? throw new ArgumentException("Valid subtype expected");
var subInstance = JsonConvert.DeserializeObject(jsonText, fieldType);
var wrapped = FSharpValue.MakeUnion(targetSubType, new [] { fieldType }, null);
return (T) wrapped;
});
Encoder<T> encoder = null; //TODO
return new Tuple<Decoder<T>, Encoder<T>>(decoder, encoder);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment