Ceiralizer 3.1.2
See the version list below for details.
dotnet add package Ceiralizer --version 3.1.2
NuGet\Install-Package Ceiralizer -Version 3.1.2
<PackageReference Include="Ceiralizer" Version="3.1.2" />
<PackageVersion Include="Ceiralizer" Version="3.1.2" />
<PackageReference Include="Ceiralizer" />
paket add Ceiralizer --version 3.1.2
#r "nuget: Ceiralizer, 3.1.2"
#:package Ceiralizer@3.1.2
#addin nuget:?package=Ceiralizer&version=3.1.2
#tool nuget:?package=Ceiralizer&version=3.1.2
Ceiralizer
A C# source-generated serialization library for converting structs and classes into compact binary data and back. Designed for network packet serialization.
NuGet:
- https://www.nuget.org/packages/Ceiralizer
- https://www.nuget.org/packages/Ceiralizer.Generator (source generator — required alongside the main package)
How It Works
Ceiralizer uses a Roslyn incremental source generator to automatically emit Serialize() and Deserialize() methods at compile time for any type implementing IPacket. Just mark fields with [PacketField] and make the type partial.
Quick Start
1. Define Your Packet
using Ceiralizer;
using Ceiralizer.Attributes;
public partial struct MyPacket : IPacket
{
[PacketField] public int Id;
[PacketField] public string Name;
[PacketField] public float[] Values;
}
2. Serialize & Deserialize
var packet = new MyPacket
{
Id = 42,
Name = "Hello",
Values = [1.5f, 2.5f, 3.0f]
};
// Serialize to byte[]
byte[] data = packet.Serialize();
// Deserialize from byte[]
MyPacket result = MyPacket.Deserialize(data);
Console.WriteLine(result.Name); // Output: Hello
Supported Field Types
| Category | Types |
|---|---|
| Primitives | bool, byte, sbyte, char |
| Integers | int, uint, short, ushort, long, ulong |
| Bit-packed | bool and integers with [PacketBitPacked] — pack into individual bits |
| Floats | float, double |
| Text | string (with configurable encoding/prefix) |
| Collections | Arrays of any supported type (dynamic or fixed-size) |
| Nested Packets | Any type implementing IPacket |
| Custom Serializable | Any type implementing ISerializable |
| Custom Serializer | Any type with an external ICustomSerializer<T> class |
[PacketBitPacked(int bitLength = 1)]
Pack boolean and integer fields into individual bits instead of their full byte size. Multiple consecutive [PacketBitPacked] fields are grouped into the minimum number of bytes needed. Only consecutive bit-packed fields are packed together — a non-bit-packed field breaks the group.
public partial struct BitPackedPacket : IPacket
{
[PacketField] [PacketBitPacked] public bool IsEnabled; // 1 bit
[PacketField] [PacketBitPacked] public bool IsVisible; // 1 bit
[PacketField] [PacketBitPacked(5)] public int Health; // 5 bits
[PacketField] public int NormalInt; // full int32
[PacketField] [PacketBitPacked] public bool IsAlive; // 1 bit
[PacketField] [PacketBitPacked(3)] public int Level; // 3 bits
}
The generator emits inline bit operations — no runtime overhead:
// Serialize (7 bits packed into 1 byte, another 4 bits into 1 byte):
byte IsEnabled_bits = (byte)0;
IsEnabled_bits = (byte)(IsEnabled_bits | (byte)(IsEnabled ? 1 : 0) << 0);
IsEnabled_bits = (byte)(IsEnabled_bits | (byte)(IsVisible ? 1 : 0) << 1);
IsEnabled_bits = (byte)(IsEnabled_bits | (byte)(Health & 0x1F) << 2);
writer.Write((byte)(IsEnabled_bits >> 0));
writer.Write(NormalInt);
byte IsAlive_bits = (byte)0;
IsAlive_bits = (byte)(IsAlive_bits | (byte)(IsAlive ? 1 : 0) << 0);
IsAlive_bits = (byte)(IsAlive_bits | (byte)(Level & 0x7) << 1);
writer.Write((byte)(IsAlive_bits >> 0));
Size reduction example: BitPackedPacket above takes 6 bytes instead of 15 (normal).
The accumulator type scales with the group size:
| Group bits | Accumulator | Bytes written |
|-----------|-------------|---------------|
| 1-8 | byte | 1 |
| 9-16 | ushort | 2 |
| 17-32 | uint | 4 |
| 33-64 | ulong | 8 |
Bit length is automatically clamped to the field type's capacity (e.g. [PacketBitPacked(100)] on a byte becomes 8).
Configuration Attributes
[PacketFieldOrder(int order)]
Control serialization order. Fields are sorted ascending (unmarked fields have implicit order -1, serialized first in declaration order).
public partial struct OrderedPacket : IPacket
{
[PacketField] [PacketFieldOrder(3)] public int Third;
[PacketField] [PacketFieldOrder(1)] public int First;
[PacketField] [PacketFieldOrder(2)] public int Second;
}
[PacketStringOptions(encoder, stringPrefixLength)]
Control string encoding and length prefix per-field or per-type.
using Ceiralizer.Models;
public partial struct StringOptionsPacket : IPacket
{
[PacketField]
[PacketStringOptions(encoder: TextEncoding.ASCII, stringPrefixLength: PrefixType.Short)]
public string AsciiShort;
[PacketField]
[PacketStringOptions(encoder: TextEncoding.Unicode)]
public string UnicodeString;
}
Apply to the type itself for a default:
[PacketStringOptions(encoder: TextEncoding.ASCII, stringPrefixLength: PrefixType.Short)]
public partial struct TypeLevelPacket : IPacket
{
[PacketField] public string Name;
}
Encoding options: ASCII, UTF7, UTF8 (default), UTF32, Unicode, BigEndianUnicode
Prefix options: Byte, SByte, Short, UShort, Int (default)
[PacketCollectionOptions(size)]
Control array serialization. size = 0 (default) = dynamic (length-prefixed). size > 0 = fixed-size (no prefix).
public partial struct CollectionOptionsPacket : IPacket
{
[PacketField] [PacketCollectionOptions(size: 0)] public int[] Dynamic;
[PacketField] [PacketCollectionOptions(size: 5)] public int[] FixedSize; // exactly 5 elements
}
Apply to the type itself:
[PacketCollectionOptions(size: 3)]
public partial struct FixedArrayPacket : IPacket
{
[PacketField] public int[] Values; // always 3 elements
}
Custom Serialization
ISerializable — Custom logic on the type itself
Implement ISerializable for types that need manual serialization:
public class FooBar : ISerializable
{
public int A { get; set; }
public string B { get; set; } = string.Empty;
public void Serialize(ChunkWriter writer)
{
writer.Write(A);
writer.Write(B.Length);
writer.Write(B, Encoding.UTF8);
}
public void Deserialize(ChunkReader reader)
{
A = reader.ReadInt();
int len = reader.ReadInt();
B = reader.ReadString(Encoding.UTF8, len);
}
}
public partial struct PacketWithSerializable : IPacket
{
[PacketField] public FooBar Data;
}
ICustomSerializer<T> — External serializer for types you don't control
public readonly record struct Vector3(float X, float Y, float Z);
public class Vector3Serializer : ICustomSerializer<Vector3>
{
public static void Serialize(Vector3 vec, ChunkWriter writer)
{
writer.Write(vec.X);
writer.Write(vec.Y);
writer.Write(vec.Z);
}
public static Vector3 Deserialize(ChunkReader reader)
{
return new Vector3(reader.ReadFloat(), reader.ReadFloat(), reader.ReadFloat());
}
}
public partial struct PacketWithCustomSerializer : IPacket
{
[PacketField] public Vector3 Position;
}
Note: Fields using
ISerializableorICustomSerializer<T>must still be marked with[PacketField].
How Serialization Works
- Source generation: At compile time, the generator produces
Serialize(ChunkWriter),Serialize()(returnsbyte[]),Deserialize(ChunkReader), andDeserialize(byte[])for everypartialtype implementingIPacket. - Field ordering: Fields are serialized in
[PacketFieldOrder]ascending order; unmarked fields come first in declaration order. - Strings: Stored as byte-length prefix (configurable) + encoded bytes.
- Arrays: Stored as element-count prefix (
int) for dynamic arrays, or no prefix for fixed-size arrays. - Bit packing: Consecutive
[PacketBitPacked]fields are packed into the minimum number of bytes using bitwise operations. Groups are written separately — a non-bit-packed field breaks the group. - Nested packets: Fields are serialized sequentially (flattened).
- Byte order: All multi-byte values are little-endian.
Binary Format Example
For a SimplePacket with fields int Id and string Name ("AB"):
[int: 256] [int: 2 (string byte length)] [bytes: "AB"]
00 01 00 00 | 02 00 00 00 | 41 42
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. 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. |
| .NET Core | netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.1 is compatible. |
| MonoAndroid | monoandroid was computed. |
| MonoMac | monomac was computed. |
| MonoTouch | monotouch was computed. |
| Tizen | tizen60 was computed. |
| Xamarin.iOS | xamarinios was computed. |
| Xamarin.Mac | xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.1
- 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 |
|---|---|---|
| 4.1.0 | 170 | 5/26/2026 |
| 4.0.1 | 159 | 5/25/2026 |
| 4.0.0 | 156 | 5/25/2026 |
| 3.2.0 | 156 | 5/23/2026 |
| 3.1.2 | 157 | 5/23/2026 |
| 3.1.1 | 155 | 5/22/2026 |
| 3.1.0 | 149 | 5/20/2026 |
| 3.0.0 | 150 | 5/14/2026 |
| 2.0.0 | 2,509 | 5/8/2026 |
| 1.1.0 | 6,638 | 1/31/2023 |
| 1.0.5 | 6,780 | 4/12/2022 |
| 1.0.4 | 6,772 | 4/10/2022 |
| 1.0.3 | 6,734 | 4/6/2022 |
| 1.0.2 | 6,736 | 2/10/2022 |
| 1.0.1 | 6,745 | 2/7/2022 |
| 1.0.0 | 6,573 | 1/7/2022 |