ToonNet.SourceGenerators
1.4.0
dotnet add package ToonNet.SourceGenerators --version 1.4.0
NuGet\Install-Package ToonNet.SourceGenerators -Version 1.4.0
<PackageReference Include="ToonNet.SourceGenerators" Version="1.4.0"> <PrivateAssets>all</PrivateAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets> </PackageReference>
<PackageVersion Include="ToonNet.SourceGenerators" Version="1.4.0" />
<PackageReference Include="ToonNet.SourceGenerators"> <PrivateAssets>all</PrivateAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets> </PackageReference>
paket add ToonNet.SourceGenerators --version 1.4.0
#r "nuget: ToonNet.SourceGenerators, 1.4.0"
#:package ToonNet.SourceGenerators@1.4.0
#addin nuget:?package=ToonNet.SourceGenerators&version=1.4.0
#tool nuget:?package=ToonNet.SourceGenerators&version=1.4.0
ToonNet.SourceGenerators
Compile-time code generation for zero-allocation TOON serialization
๐ฆ What is ToonNet.SourceGenerators?
ToonNet.SourceGenerators uses C# Source Generators to generate serialization code at compile-time:
- โ Zero Allocation - No runtime reflection or expression trees
- โ AOT Compatible - Works with Native AOT compilation
- โ Maximum Performance - Direct property access (no overhead)
- โ Type Safe - Compile-time errors for unsupported types
- โ Auto-Generated - No manual serialization code needed
Perfect for:
- โก Hot Paths - APIs with high-frequency serialization
- ๐ Performance Critical - Real-time systems, gaming, IoT
- ๐ฑ Native AOT - Self-contained executables
- ๐ฏ Zero Overhead - When every microsecond counts
๐ Quick Start
Installation
# Core package (required)
dotnet add package ToonNet.Core
# Source generators
dotnet add package ToonNet.SourceGenerators
Basic Usage
using ToonNet.Core.Serialization.Attributes;
// Mark class with [ToonSerializable]
[ToonSerializable]
public partial class Person
{
public string Name { get; set; }
public int Age { get; set; }
public List<string> Hobbies { get; set; }
}
// Use the class
var person = new Person
{
Name = "Alice",
Age = 28,
Hobbies = new List<string> { "Reading", "Coding" }
};
// Serialize using ToonSerializer (runtime)
string toon = ToonSerializer.Serialize(person);
// Deserialize using ToonSerializer (runtime)
var personBack = ToonSerializer.Deserialize<Person>(toon);
// Alternative: Use generated static methods directly
var doc = Person.Serialize(person);
var restored = Person.Deserialize(doc);
Note: Source generator creates static Serialize and Deserialize methods at compile-time. You can use them directly or through ToonSerializer for zero-allocation performance.
๐ง How It Works
Source Generator Process
- Compile-Time Analysis - Analyzes [ToonSerializable] classes
- Code Generation - Generates serialization methods
- Zero Runtime Overhead - All work done at compile-time
Generated Code Example
Your Code:
[ToonSerializable]
public partial class Product
{
public int Id { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
}
Generated Code (simplified):
// Source generator creates static Serialize and Deserialize methods
public partial class Product
{
/// <summary>
/// Serializes this instance to a TOON document (generated code).
/// </summary>
public static ToonDocument Serialize(
Product value,
ToonSerializerOptions? options = null)
{
// Direct property access with no reflection overhead
var obj = new ToonObject();
obj["Id"] = new ToonNumber(value.Id);
obj["Name"] = new ToonString(value.Name);
obj["Price"] = new ToonNumber((double)value.Price);
return new ToonDocument(obj);
}
/// <summary>
/// Deserializes a TOON document to an instance (generated code).
/// </summary>
public static Product Deserialize(
ToonDocument doc,
ToonSerializerOptions? options = null)
{
var obj = (ToonObject)doc.Root;
var result = new Product();
result.Id = (int)((ToonNumber)obj["Id"]).Value;
result.Name = ((ToonString)obj["Name"]).Value;
result.Price = (decimal)((ToonNumber)obj["Price"]).Value;
return result;
}
}
๐ Attributes
[ToonSerializable]
Marks a class for source generation:
[ToonSerializable]
public partial class MyClass
{
// Class must be partial
// Must have parameterless constructor (or primary constructor)
}
[ToonProperty]
Customizes property serialization:
[ToonSerializable]
public partial class Product
{
[ToonProperty("product_id")]
public int Id { get; set; }
public string Name { get; set; }
}
// Serializes as:
// product_id: 123
// Name: Laptop
[ToonIgnore]
Excludes properties from serialization:
[ToonSerializable]
public partial class User
{
public string Username { get; set; }
[ToonIgnore]
public string PasswordHash { get; set; } // Not serialized
}
โก Performance Comparison
Benchmark Results
BenchmarkDotNet v0.13.12, Windows 11
Intel Core i7-12700K, 1 CPU, 12 logical and 8 physical cores
.NET SDK 8.0.100
| Method | Mean | Allocated |
|-------------------------- |----------:|----------:|
| SourceGenerator_Serialize | 45.2 ns | - | โ Zero allocation!
| ExpressionTree_Serialize | 89.5 ns | 120 B |
| Reflection_Serialize | 4,250 ns | 856 B |
Source Generator is:
- 2x faster than Expression Trees
- 94x faster than Reflection
- Zero heap allocations (hot path)
When to Use Source Generators
โ Use Source Generators When:
- Hot path with high-frequency serialization
- AOT compilation required
- Zero-allocation is critical
- Startup performance matters
โ ๏ธ Use Runtime Serialization When:
- Types unknown at compile-time
- Dynamic type loading (plugins)
- Reflection-based scenarios
- Generic/flexible serialization
๐ฏ Real-World Examples
Example 1: High-Performance API
using ToonNet.Core.Serialization;
using ToonNet.Core.Serialization.Attributes;
[ToonSerializable]
public partial class ApiResponse
{
public int StatusCode { get; set; }
public string Message { get; set; }
public DateTime Timestamp { get; set; }
}
[ApiController]
[Route("api/[controller]")]
public class DataController : ControllerBase
{
[HttpGet]
public IActionResult GetData()
{
var response = new ApiResponse
{
StatusCode = 200,
Message = "Success",
Timestamp = DateTime.UtcNow
};
// Zero-allocation serialization (source generator optimized)
var toon = ToonSerializer.Serialize(response);
return Content(toon, "application/toon");
}
}
Example 2: Gaming/Real-Time Systems
using ToonNet.Core.Serialization;
using ToonNet.Core.Serialization.Attributes;
[ToonSerializable]
public partial class PlayerState
{
public int PlayerId { get; set; }
public Vector3 Position { get; set; }
public float Health { get; set; }
public int Score { get; set; }
}
public class NetworkManager
{
public void BroadcastState(PlayerState state)
{
// Critical path - zero allocations
string data = ToonSerializer.Serialize(state);
networkSocket.Send(data);
}
public PlayerState ReceiveState(string data)
{
// Fast deserialization
return ToonSerializer.Deserialize<PlayerState>(data);
}
}
Example 3: IoT/Embedded Systems
using ToonNet.Core.Serialization;
using ToonNet.Core.Serialization.Attributes;
[ToonSerializable]
public partial class SensorReading
{
public DateTime Timestamp { get; set; }
public double Temperature { get; set; }
public double Humidity { get; set; }
public int BatteryLevel { get; set; }
}
public class SensorDevice
{
public void SendTelemetry()
{
var reading = new SensorReading
{
Timestamp = DateTime.UtcNow,
Temperature = ReadTemperature(),
Humidity = ReadHumidity(),
BatteryLevel = GetBatteryLevel()
};
// Minimal memory footprint
var payload = ToonSerializer.Serialize(reading);
mqttClient.Publish("sensors/data", payload);
}
}
Example 4: Native AOT Application
// Project file configuration
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<PublishAot>true</PublishAot>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="ToonNet.Core" />
<PackageReference Include="ToonNet.SourceGenerators" />
</ItemGroup>
</Project>
// Code
using ToonNet.Core.Serialization;
using ToonNet.Core.Serialization.Attributes;
[ToonSerializable]
public partial class Config
{
public string AppName { get; set; }
public int MaxConnections { get; set; }
}
// Works with Native AOT (no reflection!)
var config = new Config { AppName = "MyApp", MaxConnections = 100 };
var toon = ToonSerializer.Serialize(config);
๐ Supported Types
Primitive Types
string,int,long,short,byte,sbyteuint,ulong,ushortfloat,double,decimalbool,char,Guid,DateTime,DateTimeOffset
Collections
List<T>,T[]Dictionary<TKey, TValue>IEnumerable<T>,IList<T>,ICollection<T>
Complex Types
- Nested classes with
[ToonSerializable] - Nullable types (
int?,DateTime?) - Enums
Limitations
โ Not Supported:
- Abstract/interface types
- Circular references
- Types without parameterless constructor
- Generic types (not instantiated)
๐ Thread-Safety
- Generated serializers and
ToonSerializermethods are safe to call concurrently across threads. - Shared metadata/name caches use
ConcurrentDictionaryfor concurrent access. - Cache entries are created on demand and retained for the process lifetime (no eviction).
- Do not mutate a single
ToonSerializerOptionsinstance concurrently across threads.
๐งช Testing
# Run source generator tests
cd tests/ToonNet.SourceGenerators.Tests
dotnet test
# Verify generated code
dotnet build --verbosity detailed
# Check obj/Debug/net8.0/generated/ folder
๐ Related Packages
Core:
ToonNet.Core- Core serialization (required)
Extensions:
ToonNet.Extensions.Json- JSON โ TOONToonNet.Extensions.Yaml- YAML โ TOON
Web:
ToonNet.AspNetCore- ASP.NET Core DIToonNet.AspNetCore.Mvc- MVC formatters
Development:
ToonNet.Benchmarks- Performance testsToonNet.Tests- Test suite
๐ Documentation
- Main Documentation - Complete guide
- API Guide - API reference
- Benchmarks - Performance data
๐ Requirements
- .NET 8.0 or later
- C# 12.0+ (for partial classes)
- ToonNet.Core
๐ License
MIT License - See LICENSE file for details.
๐ค Contributing
Contributions welcome! Please read CONTRIBUTING.md first.
Part of the ToonNet serialization library family.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net8.0
- ToonNet.Core (>= 1.4.0)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
v1.4.0: Updated to support ToonNet.Core 1.4.0 streaming features.