Skip to content

Instantly share code, notes, and snippets.

@sgoguen
Created November 13, 2024 00:42
Show Gist options
  • Save sgoguen/15a8ecf04c92a3b3bc59a8227b372b7a to your computer and use it in GitHub Desktop.
Save sgoguen/15a8ecf04c92a3b3bc59a8227b372b7a to your computer and use it in GitHub Desktop.
Hello PolyType
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