Tessera.Serialization 0.1.1-preview

This is a prerelease version of Tessera.Serialization.
dotnet add package Tessera.Serialization --version 0.1.1-preview
                    
NuGet\Install-Package Tessera.Serialization -Version 0.1.1-preview
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Tessera.Serialization" Version="0.1.1-preview" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Tessera.Serialization" Version="0.1.1-preview" />
                    
Directory.Packages.props
<PackageReference Include="Tessera.Serialization" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Tessera.Serialization --version 0.1.1-preview
                    
#r "nuget: Tessera.Serialization, 0.1.1-preview"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Tessera.Serialization@0.1.1-preview
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Tessera.Serialization&version=0.1.1-preview&prerelease
                    
Install as a Cake Addin
#tool nuget:?package=Tessera.Serialization&version=0.1.1-preview&prerelease
                    
Install as a Cake Tool

Tessera.Serialization

Binary buffers from plain .NET objects, read in place by C++20 and .NET: no schema file, no parsing, and no allocations on the read side. This package holds the .NET library, the source generator that writes a serializer for each of your classes, the tool that writes their C++ headers after each build, and the header-only C++20 library those headers use.

Example

Your C# classes are the schema:

namespace Game;

public class Monster
{
    public string? Name;
    public short Hp = 100;            // equal to its default: not stored
    public int? Mana;                 // nullable: C++ can tell whether it was set
    public Vec3 Position;             // plain struct: stored inline
    public List<Weapon>? Weapons;
}

public class Weapon { public string? Name; public int Damage; }

public record struct Vec3(float X, float Y, float Z);

Save one. That call is all the source generator needs: it writes a serializer for Monster and for every type Monster uses.

using Game;
using Tessera;

var orc = new Monster
{
    Name = "Orc",
    Mana = 25,
    Position = new Vec3(1, 2, 3),
    Weapons = [new() { Name = "Axe", Damage = 9 }, new() { Name = "Bow", Damage = 4 }],
};

byte[] buffer = TesseraSerializer.Serialize(orc);
File.WriteAllBytes("monster.bin", buffer);
Console.WriteLine($"{buffer.Length} bytes");
328 bytes

The same build writes a C++ header for each class. C++ verifies the buffer once, then reads it where it lies:

#include "game/Monster.tessera.hpp"

// data, size: the 328 bytes of monster.bin, in 8-byte aligned memory
tessera::Reader<game::Monster> reader(data, size);  // verifies the buffer once
if (!reader) return 1;

game::Monster orc = reader.root();  // a view: reads in place, nothing is parsed or copied
const game::Vec3& p = orc.position();
std::cout << orc.name() << ": hp " << orc.hp() << ", mana " << orc.mana().value_or(0)
          << ", position " << p.x << ' ' << p.y << ' ' << p.z << '\n';
for (game::Weapon w : orc.weapons()) std::cout << "  " << w.name() << ": damage " << w.damage() << '\n';
Orc: hp 100, mana 25, position 1 2 3
  Axe: damage 9
  Bow: damage 4

.NET reads the buffer in place too, through a read type generated for each class (MonsterView for Monster), or creates the objects again:

MonsterView view = MonsterView.Read(buffer);   // checks the buffer once; copies nothing
Vec3 p = view.Position;
Console.WriteLine($"{view.Name}: hp {view.Hp}, mana {view.Mana}, position {p.X} {p.Y} {p.Z}");
foreach (WeaponView w in view.Weapons) Console.WriteLine($"  {w.Name}: damage {w.Damage}");

Monster copy = TesseraSerializer.Deserialize<Monster>(buffer);
Console.WriteLine($"{copy.Name} again, with {copy.Weapons!.Count} weapons");
Orc: hp 100, mana 25, position 1 2 3
  Axe: damage 9
  Bow: damage 4
Orc again, with 2 weapons

Setup

dotnet add package Tessera.Serialization --prerelease

Then choose where the C++ headers go, in your project file:

<PropertyGroup>
  <TesseraCppOutputDir>cpp/generated</TesseraCppOutputDir>
</PropertyGroup>

After each build, that folder holds a header for each class and the C++ runtime headers: add it to your C++ include path. Buffers must start at an 8-byte aligned address, as memory from new, malloc or a std::vector<std::uint64_t> does. Without TesseraCppOutputDir, no headers are written to disk.

Why Tessera

  • Your classes are the schema. No separate schema file and no required attributes: classes, records, structs, enums, nullable values, lists, dictionaries, and fields declared as an abstract class or interface, which can hold any derived class. Types that can't be saved are reported at compile time, with a suggested replacement.
  • No parsing. C++ and .NET validate a buffer once; after that, every field read is a plain memory load: nothing is parsed, copied or allocated.
  • Versioning by name. Add, remove, reorder and rename fields, with no field numbers to manage: older and newer programs read each other's data.
  • Compact. Fields that are null or equal to their default take no space, and equal strings are stored once.
  • Measured. Benchmarked against FlatBuffers, MessagePack, Protocol Buffers, JSON and MemoryPack, in .NET and C++: see the results.

Documentation

Tessera is a preview: the API and the wire format may change before 1.0. It is released under the Apache License 2.0.

Product 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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • net8.0

    • No dependencies.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
0.1.1-preview 42 10/17/2026
0.1.0-preview 46 10/17/2026