Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/eiriktsarpalis/PolyType
Practical generic programming for C#
https://github.com/eiriktsarpalis/PolyType
Last synced: 30 days ago
JSON representation
Practical generic programming for C#
- Host: GitHub
- URL: https://github.com/eiriktsarpalis/PolyType
- Owner: eiriktsarpalis
- License: mit
- Created: 2022-07-03T15:41:08.000Z (over 2 years ago)
- Default Branch: main
- Last Pushed: 2024-11-08T16:04:03.000Z (about 1 month ago)
- Last Synced: 2024-11-08T16:41:14.972Z (about 1 month ago)
- Language: C#
- Homepage: https://eiriktsarpalis.github.io/typeshape-csharp/
- Size: 1.33 MB
- Stars: 141
- Watchers: 8
- Forks: 6
- Open Issues: 7
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
- RSCG_Examples - https://github.com/eiriktsarpalis/PolyType
README
# PolyType [![Build & Tests](https://github.com/eiriktsarpalis/PolyType/actions/workflows/build.yml/badge.svg)](https://github.com/eiriktsarpalis/PolyType/actions/workflows/build.yml) [![NuGet Badge](https://img.shields.io/nuget/dt/PolyType)](https://www.nuget.org/packages/PolyType/)
PolyType is a practical datatype-generic programming library for .NET types. It is a direct adaptation of the [TypeShape](https://github.com/eiriktsarpalis/TypeShape) library for F#, adapted to patterns and idioms available in C#. See the [project website](https://eiriktsarpalis.github.io/PolyType) for additional background and [API documentation](https://eiriktsarpalis.github.io/PolyType/api/PolyType.html).
The project is named after [polytypic programming](https://en.wikipedia.org/wiki/Polymorphism_(computer_science)#Polytypism), another term used to describe datatype-generic programming.
## Quick Start
You can try the library by installing the `PolyType` NuGet package:
```bash
$ dotnet add package PolyType
```which includes the core types and source generator for generating type shapes:
```C#
using PolyType;[GenerateShape]
public partial record Person(string name, int age);
```Doing this will augment `Person` with an implementation of the `IShapeable` interface. This suffices to make `Person` usable with any library that targets the PolyType core abstractions. You can try this out by installing the built-in example libraries:
```bash
$ dotnet add package PolyType.Examples
```Here's how the same value can be serialized to three separate formats.
```csharp
using PolyType.Examples.JsonSerializer;
using PolyType.Examples.CborSerializer;
using PolyType.Examples.XmlSerializer;Person person = new("Pete", 70);
JsonSerializerTS.Serialize(person); // {"Name":"Pete","Age":70}
XmlSerializer.Serialize(person); // Pete70
CborSerializer.EncodeToHex(person); // A2644E616D656450657465634167651846
```Since the application uses a source generator to produce the shape for `Person`, it is fully compatible with Native AOT. See the [shape providers](https://eiriktsarpalis.github.io/PolyType/shape-providers.html) article for more details on how to use the library with your types.
## Introduction
PolyType is a meta-library that facilitates rapid development of high performance datatype-generic programs. It exposes a simplified model for .NET types that makes it easy for library authors to publish production-ready components in just a few lines of code. The built-in source generator ensures that any library built on top of the PolyType abstractions gets Native AOT support for free.
As a library author, PolyType lets you write high performance, feature complete generic components that target its [core abstractions](https://eiriktsarpalis.github.io/PolyType/core-abstractions.html). For example, a parser API using PolyType might look as follows:
```C#
public static class MyFancyParser
{
public static T? Parse(string myFancyFormat) where T : IShapeable;
}
```As an end user, PolyType lets you generate shape models for your own types that can be used with one or more supported libraries:
```C#
Person? person = MyFancyParser.Parse(format); // Compiles[GenerateShape] // Generate an IShapeable implementation
partial record Person(string name, int age, List children);
```For more information see:
* The [core abstractions](https://eiriktsarpalis.github.io/PolyType/core-abstractions.html) document for an overview of the core programming model.
* The [shape providers](https://eiriktsarpalis.github.io/PolyType/shape-providers.html) document for an overview of the built-in shape providers and their APIs.
* The generated [API documentation](https://eiriktsarpalis.github.io/PolyType/api/PolyType.html) for the project.
* The [`PolyType.Examples`](https://github.com/eiriktsarpalis/PolyType/tree/main/src/PolyType.Examples) project for advanced examples of libraries built on top of PolyType.## Case Study: Writing a JSON serializer
The repo includes a [JSON serializer](https://github.com/eiriktsarpalis/PolyType/tree/main/src/PolyType.Examples/JsonSerializer) built on top of the `Utf8JsonWriter`/`Utf8JsonReader` primitives provided by System.Text.Json. At the time of writing, the full implementation is just under 1200 lines of code but exceeds STJ's built-in `JsonSerializer` both in terms of [supported types](https://github.com/eiriktsarpalis/PolyType/blob/main/tests/PolyType.Tests/JsonTests.cs) and performance.
### Performance
Here's a [benchmark](https://github.com/eiriktsarpalis/PolyType/blob/main/tests/PolyType.Benchmarks/JsonBenchmark.cs) comparing `System.Text.Json` with the included PolyType implementation:
#### Serialization
| Method | Mean | Ratio | Allocated | Alloc Ratio |
|-------------------------------- |---------:|------:|----------:|------------:|
| Serialize_StjReflection | 491.9 ns | 1.00 | 312 B | 1.00 |
| Serialize_StjSourceGen | 467.0 ns | 0.95 | 312 B | 1.00 |
| Serialize_StjSourceGen_FastPath | 227.2 ns | 0.46 | - | 0.00 |
| Serialize_PolyTypeReflection | 277.9 ns | 0.57 | - | 0.00 |
| Serialize_PolyTypeSourceGen | 273.6 ns | 0.56 | - | 0.00 |#### Deserialization
| Method | Mean | Ratio | Allocated | Alloc Ratio |
|-------------------------------- |-----------:|------:|----------:|------------:|
| Deserialize_StjReflection | 1,593.0 ns | 1.00 | 1024 B | 1.00 |
| Deserialize_StjSourceGen | 1,530.3 ns | 0.96 | 1000 B | 0.98 |
| Deserialize_PolyTypeReflection | 773.1 ns | 0.49 | 440 B | 0.43 |
| Deserialize_PolyTypeSourceGen | 746.7 ns | 0.47 | 440 B | 0.43 |Even though both serializers target the same underlying reader and writer types, the PolyType implementation is ~75% faster for serialization and ~100% faster for deserialization, when compared with System.Text.Json's metadata serializer. As expected, fast-path serialization is still fastest since its implementation is fully inlined.
## Known libraries based on PolyType
The following code bases are based upon PolyType and may be worth checking out.
* [Nerdbank.MessagePack](https://github.com/AArnott/Nerdbank.MessagePack) - a MessagePack library with performance to rival MessagePack-CSharp, and greater simplicity and additional features.
## Project structure
The repo consists of the following projects:
* The core `PolyType` library containing:
* The [core abstractions](https://github.com/eiriktsarpalis/PolyType/tree/main/src/PolyType/Abstractions) defining the type model.
* The [reflection provider](https://github.com/eiriktsarpalis/PolyType/tree/main/src/PolyType/ReflectionProvider) implementation.
* The [model classes](https://github.com/eiriktsarpalis/PolyType/tree/main/src/PolyType/SourceGenModel) used by the source generator.
* The [`PolyType.SourceGenerator`](https://github.com/eiriktsarpalis/PolyType/tree/main/src/PolyType.SourceGenerator) project contains the built-in source generator implementation.
* The [`PolyType.Roslyn`](https://github.com/eiriktsarpalis/PolyType/tree/main/src/PolyType.Roslyn) library exposes a set of components for extracting data models from Roslyn type symbols. Used as the foundation for the built-in source generator.
* [`PolyType.Examples`](https://github.com/eiriktsarpalis/PolyType/tree/main/src/PolyType.Examples) containing library examples:
* A serializer built on top of System.Text.Json,
* A serializer built on top of System.Xml,
* A serializer built on top of System.Formats.Cbor,
* A `ConfigurationBinder` like implementation,
* A simple pretty-printer for .NET values,
* A generic random value generator based on `System.Random`,
* A JSON schema generator for .NET types,
* An object cloning function,
* A structural `IEqualityComparer` generator for POCOs and collections,
* An object validator in the style of System.ComponentModel.DataAnnotations.
* A simple .NET object mapper.
* The [`applications`](https://github.com/eiriktsarpalis/PolyType/tree/main/applications) folder contains sample Native AOT console applications.