Created
November 13, 2024 00:42
-
-
Save sgoguen/15a8ecf04c92a3b3bc59a8227b372b7a to your computer and use it in GitHub Desktop.
Hello PolyType
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
namespace PolyTypeExample; | |
using PolyType; | |
using PolyType.Abstractions; | |
using PolyType.Examples.Utilities; | |
public class Examples | |
{ | |
// public static void | |
} | |
[GenerateShape] | |
public partial record Person(string Name, int Age, Person?[] Friends); | |
public class Program | |
{ | |
public static void Main() | |
{ | |
Person bob = new Person("Bob", 21, []); | |
Person larry = new("Pete", 70, [bob, bob]); | |
Person jim = new("Pete", 70, [larry, larry]); | |
PolyType.Examples.JsonSerializer.JsonSerializerTS.Serialize(larry).Dump(); // {"Name":"Pete","Age":70} | |
PolyType.Examples.XmlSerializer.XmlSerializer.Serialize(larry).Dump(); // <value><Name>Pete</Name><Age>70</Age></value> | |
PolyType.Examples.CborSerializer.CborSerializer.EncodeToHex(larry).Dump(); // A2644E616D656450657465634167651846 | |
Counter.Count(jim).Dump(); | |
} | |
} | |
public static class DumpUtil { | |
public static void Dump(this object? obj) => Console.WriteLine(obj); | |
} | |
public delegate int Counter<in T>(T input); | |
public static partial class Counter | |
{ | |
public static Counter<T> Create<T>(ITypeShape<T> shape) => new CounterVisitor().BuildCounter<T>(shape); | |
public static int Count<T>(T? value) where T : IShapeable<T> | |
=> value == null ? 0 : CounterCache<T, T>.Value.Invoke(value); | |
private static class CounterCache<T, TProvider> where TProvider : IShapeable<T> | |
{ | |
public static Counter<T> Value => s_value ??= Create(TProvider.GetShape()); | |
private static Counter<T>? s_value; | |
} | |
} | |
partial class CounterVisitor : TypeShapeVisitor | |
{ | |
private static readonly Dictionary<Type, object> s_defaultPrinters = new(CreateDefaultCounters()); | |
private readonly TypeDictionary _cache = new(); | |
public Counter<T> BuildCounter<T>(ITypeShape<T> typeShape) | |
{ | |
if (s_defaultPrinters.TryGetValue(typeShape.Type, out object? defaultPrinter)) | |
{ | |
return (Counter<T>)defaultPrinter; | |
} | |
//return _cache.GetOrAdd<Counter<T>>(typeShape, this, dela | |
return _cache.GetOrAdd<Counter<T>>( | |
typeShape, | |
this, | |
delayedValueFactory: self => new Counter<T>((value) => self.Result(value))); | |
} | |
public override object? VisitObject<T>(IObjectTypeShape<T> objectShape, object? state = null) | |
{ | |
// Generate counter delegates for each individual property or field: | |
Counter<T>[] propertyCounters = objectShape.GetProperties() | |
.Where(prop => prop.HasGetter) | |
.Select(prop => (Counter<T>)prop.Accept(this)!) | |
.ToArray(); | |
// Compose into a counter delegate for the current type. | |
return new Counter<T?>(value => | |
{ | |
if (value is null) | |
return 0; | |
int count = 1; | |
foreach (Counter<T> propertyCounter in propertyCounters) | |
count += propertyCounter(value); | |
return count; | |
}); | |
} | |
public override object? VisitProperty<TDeclaringType, TPropertyType>(IPropertyShape<TDeclaringType, TPropertyType> propertyShape, object? _) | |
{ | |
Getter<TDeclaringType, TPropertyType> getter = propertyShape.GetGetter(); // extract the getter delegate | |
var propertyTypeCounter = (Counter<TPropertyType>)propertyShape.PropertyType.Accept(this)!; // extract the counter for the property shape | |
return new Counter<TDeclaringType>(obj => propertyTypeCounter(getter(ref obj))); // combine into a property-specific counter delegate | |
} | |
public override object? VisitEnumerable<TEnumerable, TElement>(IEnumerableTypeShape<TEnumerable, TElement> enumerableShape, object? state = null) | |
{ | |
Func<TEnumerable, IEnumerable<TElement>> enumerableGetter = enumerableShape.GetGetEnumerable(); | |
Counter<TElement> elementCounter = BuildCounter(enumerableShape.ElementType); | |
bool valuesArePrimitives = s_defaultPrinters.ContainsKey(typeof(TElement)); | |
return new Counter<TEnumerable>(enumerable => | |
{ | |
if (enumerable is null) | |
return 0; | |
int count = 0; | |
foreach (var element in enumerableGetter(enumerable)) | |
{ | |
count += elementCounter(element); | |
} | |
return count; | |
}); | |
} | |
public static IEnumerable<KeyValuePair<Type, object>> CreateDefaultCounters() | |
{ | |
yield return Create<string>((s) => (s == null) ? 0 : 1); | |
yield return Create<int>((s) => (s == 0) ? 0 : 1); | |
static KeyValuePair<Type, object> Create<T>(Counter<T> printer) | |
=> new(typeof(T), printer); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment