Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/ProwlEngine/Prowl.Echo/llms.txt

Use this file to discover all available pages before exploring further.

Prowl.Echo separates the serialization of .NET objects into EchoObject trees from the encoding of those trees into bytes or text. The file format layer handles the second step. Six built-in IFileFormat implementations cover the most common encoding targets: a compact proprietary binary format, a human-readable proprietary text format, JSON, BSON, YAML, and XML. All six expose a static Instance singleton and implement the IFileFormat interface, so every extension method from FileFormatExtensions works with all of them. This page also documents TypeNameRegistry, the auxiliary API that controls how type names are compacted and resolved during serialization.

EchoBinaryFormat

EchoBinaryFormat is the recommended format when file size and read/write speed matter more than human readability. It preserves all EchoObject types exactly during a roundtrip — no precision is lost for any numeric type. Internally it uses LZW compression on string keys when Size mode is selected.
public sealed class EchoBinaryFormat : IFileFormat
{
    public static readonly EchoBinaryFormat Instance;
    public BinarySerializationOptions Options { get; set; }

    // IFileFormat
    public void WriteTo(EchoObject tag, Stream stream);
    public EchoObject ReadFrom(Stream stream);

    // Static direct methods (operate on BinaryReader / BinaryWriter / FileInfo)
    public static void WriteTo(EchoObject tag, BinaryWriter writer,
        BinarySerializationOptions? options = null);
    public static void WriteToFile(EchoObject tag, FileInfo file,
        BinarySerializationOptions? options = null);
    public static EchoObject ReadFrom(BinaryReader reader,
        BinarySerializationOptions? options = null);
    public static EchoObject ReadFromFile(FileInfo file,
        BinarySerializationOptions? options = null);
}

BinarySerializationOptions

public class BinarySerializationOptions
{
    public BinaryEncodingMode EncodingMode { get; set; } // default: Performance
    public static BinarySerializationOptions Default { get; }
}
EncodingMode
BinaryEncodingMode
Controls the integer encoding strategy used for all integer-typed EchoObject values.

BinaryEncodingMode

ValueDescription
PerformanceFixed-width integer encoding. Faster read/write; larger output. This is the default.
SizeLEB128 variable-length integer encoding plus LZW compression for string keys. Smaller output; slightly slower.

Usage

// Using the singleton (Performance mode by default)
byte[] bytes = EchoBinaryFormat.Instance.WriteToBytes(echoObj);
EchoObject restored = EchoBinaryFormat.Instance.ReadFromBytes(bytes);

// With Size mode
var sizeFormat = new EchoBinaryFormat
{
    Options = new BinarySerializationOptions
    {
        EncodingMode = BinaryEncodingMode.Size
    }
};
byte[] compact = sizeFormat.WriteToBytes(echoObj);

// Direct static methods — write to / read from FileInfo
EchoBinaryFormat.WriteToFile(echoObj, new FileInfo("save.bin"));
EchoObject loaded = EchoBinaryFormat.ReadFromFile(new FileInfo("save.bin"));

// Direct static methods — write to / read from BinaryWriter / BinaryReader
using var writer = new BinaryWriter(File.Create("data.bin"));
EchoBinaryFormat.WriteTo(echoObj, writer,
    new BinarySerializationOptions { EncodingMode = BinaryEncodingMode.Size });
Use BinaryEncodingMode.Performance for runtime data (saves, replays) where throughput is important. Use BinaryEncodingMode.Size for assets distributed to end users where download bandwidth matters.

EchoTextFormat

EchoTextFormat is Prowl.Echo’s native human-readable text format. Like EchoBinaryFormat, it preserves all EchoObject types exactly during a roundtrip — every numeric suffix and tag type is encoded explicitly, so no precision is lost. It is the best choice when you need a text file that can be diffed in version control without any loss of fidelity.
public sealed class EchoTextFormat : IFileFormat
{
    public static readonly EchoTextFormat Instance;

    // IFileFormat
    public void WriteTo(EchoObject tag, Stream stream);
    public EchoObject ReadFrom(Stream stream);

    // Static convenience methods
    public static string Write(EchoObject tag);
    public static EchoObject Read(string input);
    public static void WriteToFile(EchoObject tag, FileInfo file);
    public static EchoObject ReadFromFile(FileInfo file);
}
EchoText uses JSON-like { } for compounds and [ ] for lists, with type-suffix notation for numeric values (e.g., 42 is int, 42L is long, 3.14F is float).

Usage

// Via IFileFormat / extension methods
string text = EchoTextFormat.Instance.WriteToString(echoObj);
EchoObject restored = EchoTextFormat.Instance.ReadFromString(text);

// Via static helpers
string text2 = EchoTextFormat.Write(echoObj);
EchoObject from = EchoTextFormat.Read(text2);

// Via EchoObject convenience methods (same as above)
string s = echoObj.WriteToString();         // EchoObject extension — uses EchoTextFormat
EchoObject r = EchoObject.ReadFromString(s);
EchoObject.WriteToString() and EchoObject.ReadFromString() are direct static methods on EchoObject defined in EchoObject.cs and use EchoTextFormat internally. They are distinct from the IFileFormat extension methods of the same name, which accept any IFileFormat as the receiver.

JsonFileFormat

JsonFileFormat writes standard, dependency-free JSON and can read both Echo-produced JSON and generic JSON from any other source. Because JSON has fewer numeric types than EchoObject, some type precision is lost on roundtrip: byte and short round-trip as int, float round-trips as double, and ByteArray values are Base64-encoded strings. Use EchoTextFormat or EchoBinaryFormat if exact type preservation is required.
public sealed class JsonFileFormat : IFileFormat
{
    public static readonly JsonFileFormat Instance;

    /// Whether to indent the output for readability. Default: true.
    public bool Indented { get; set; }

    // IFileFormat
    public void WriteTo(EchoObject tag, Stream stream);
    public EchoObject ReadFrom(Stream stream);
}
EchoObject exposes two shortcut methods that delegate to JsonFileFormat.Instance:
// On any EchoObject instance:
public string WriteToJson();

// Static factory:
public static EchoObject ReadFromJson(string json);

Usage

// Via EchoObject shortcuts
string json = echoObj.WriteToJson();
EchoObject restored = EchoObject.ReadFromJson(json);

// Via IFileFormat / extension methods
string json2 = JsonFileFormat.Instance.WriteToString(echoObj);
EchoObject r2  = JsonFileFormat.Instance.ReadFromString(json2);

// Write to file
JsonFileFormat.Instance.WriteToFile(echoObj, "data.json");

// Compact (non-indented) output
var compact = new JsonFileFormat { Indented = false };
string minified = compact.WriteToString(echoObj);

BsonFileFormat

BsonFileFormat implements the BSON specification with no external dependencies. BSON is a binary encoding of JSON-like documents, useful when you need binary output but also interoperability with MongoDB or other BSON consumers. Type precision losses are similar to JSON: byte/short become int32, float becomes double, and decimal is stored as a string to preserve precision.
public sealed class BsonFileFormat : IFileFormat
{
    public static readonly BsonFileFormat Instance;

    // IFileFormat
    public void WriteTo(EchoObject tag, Stream stream);
    public EchoObject ReadFrom(Stream stream);
}
EchoObject exposes two shortcut methods that delegate to BsonFileFormat.Instance:
public byte[] WriteToBson();
public static EchoObject ReadFromBson(byte[] bson);
BSON requires a document at the top level. When you pass a non-Compound EchoObject to WriteTo or WriteToBson, the format automatically wraps it in a single-key document with the key __echo_wrapped_value__ and unwraps it transparently on read.

Usage

// Via EchoObject shortcuts
byte[] bson = echoObj.WriteToBson();
EchoObject restored = EchoObject.ReadFromBson(bson);

// Via IFileFormat / extension methods
byte[] bson2 = BsonFileFormat.Instance.WriteToBytes(echoObj);
EchoObject r2  = BsonFileFormat.Instance.ReadFromBytes(bson2);

// Write to file
BsonFileFormat.Instance.WriteToFile(echoObj, "data.bson");

YamlFileFormat

YamlFileFormat writes clean, human-readable YAML and can parse both Echo-produced YAML and generic YAML from other tools. Implemented without external dependencies. Type precision is reduced similarly to JSON: numeric types resolve to int, long, or double on read, and ByteArray values are encoded using the !!binary tag. Use EchoTextFormat or EchoBinaryFormat for lossless roundtrips.
public sealed class YamlFileFormat : IFileFormat
{
    public static readonly YamlFileFormat Instance;

    // IFileFormat
    public void WriteTo(EchoObject tag, Stream stream);
    public EchoObject ReadFrom(Stream stream);
}
EchoObject exposes two shortcut methods that delegate to YamlFileFormat.Instance:
public string WriteToYaml();
public static EchoObject ReadFromYaml(string yaml);

Usage

// Via EchoObject shortcuts
string yaml = echoObj.WriteToYaml();
EchoObject restored = EchoObject.ReadFromYaml(yaml);

// Via IFileFormat / extension methods
string yaml2 = YamlFileFormat.Instance.WriteToString(echoObj);
EchoObject r2  = YamlFileFormat.Instance.ReadFromString(yaml2);

// Write to file
YamlFileFormat.Instance.WriteToFile(echoObj, "config.yaml");

XmlFileFormat

XmlFileFormat writes well-formed XML with explicit type attributes that preserve all EchoObject types during a roundtrip. It can also read generic XML that lacks type attributes, in which case it infers types from the text content. Implemented without external dependencies.
public sealed class XmlFileFormat : IFileFormat
{
    public static readonly XmlFileFormat Instance;

    // IFileFormat
    public void WriteTo(EchoObject tag, Stream stream);
    public EchoObject ReadFrom(Stream stream);
}
Output includes an XML declaration (<?xml version="1.0" encoding="utf-8"?>) and wraps the root EchoObject in an <echo> element. Compound keys that are not valid XML element names are sanitized, with the original key preserved in a key attribute. EchoObject exposes two shortcut methods that delegate to XmlFileFormat.Instance:
public string WriteToXml();
public static EchoObject ReadFromXml(string xml);

Usage

// Via EchoObject shortcuts
string xml = echoObj.WriteToXml();
EchoObject restored = EchoObject.ReadFromXml(xml);

// Via IFileFormat / extension methods
string xml2 = XmlFileFormat.Instance.WriteToString(echoObj);
EchoObject r2  = XmlFileFormat.Instance.ReadFromString(xml2);

// Write to file
XmlFileFormat.Instance.WriteToFile(echoObj, "config.xml");

FileFormatExtensions

FileFormatExtensions is a static class providing convenience extension methods that wrap IFileFormat.WriteTo and IFileFormat.ReadFrom. These methods are available on every IFileFormat — including your own custom implementations.
public static class FileFormatExtensions
{
    public static string     WriteToString(this IFileFormat format, EchoObject tag);
    public static EchoObject ReadFromString(this IFileFormat format, string input);
    public static byte[]     WriteToBytes(this IFileFormat format, EchoObject tag);
    public static EchoObject ReadFromBytes(this IFileFormat format, byte[] data);
    public static void       WriteToFile(this IFileFormat format, EchoObject tag, string path);
    public static EchoObject ReadFromFile(this IFileFormat format, string path);
}
MethodReturnsNotes
WriteToString(tag)stringEncodes via a MemoryStream and reads back with UTF-8. Best for text formats.
ReadFromString(input)EchoObjectConverts the string to UTF-8 bytes, then calls ReadFrom.
WriteToBytes(tag)byte[]Writes to a MemoryStream and returns its buffer. Works for any format.
ReadFromBytes(data)EchoObjectWraps data in a MemoryStream and calls ReadFrom.
WriteToFile(tag, path)voidCreates or overwrites the file at path.
ReadFromFile(path)EchoObjectOpens the file at path for reading.

TypeNameRegistry

TypeNameRegistry manages the compact and full type-name mappings that Echo writes into EchoObject compounds when preserving polymorphic type information. It caches all lookups in thread-safe concurrent dictionaries for performance.
public static class TypeNameRegistry
{
    public static string  GetCompactTypeName(Type type);
    public static Type?   ResolveCompactTypeName(string name);
    public static string  GetFullTypeName(Type type);
    public static Type?   ResolveFullTypeName(string name);
    public static void    ClearCache();
}

Methods

GetCompactTypeName(Type type)
string
Returns the shortest possible name for a type. For the predefined primitives this is a single-character or two-character alias. For enums it is e:EnumName. For arrays it is elementName[] or elementName[,] for multi-dimensional arrays. For generic types it is TypeName<argName1,argName2>. For everything else it falls back to Type.Name.
ResolveCompactTypeName(string name)
Type?
Resolves a compact name back to a Type. Returns null if resolution fails.
GetFullTypeName(Type type)
string
Returns the assembly-qualified name (Type.AssemblyQualifiedName), falling back to FullName and then Name if the qualified name is unavailable.
ResolveFullTypeName(string name)
Type?
Resolves an assembly-qualified name via Type.GetType, falling back to a reflection scan of all loaded assemblies. Returns null on failure.
ClearCache
void
Evicts all entries from the compact-name, full-name, and lookup caches. Call this if you hot-reload assemblies or otherwise change the set of types visible to reflection.

Predefined compact names

The following compact aliases are built into TypeNameRegistry and do not require any registration:
.NET typeCompact name
int"i"
string"s"
bool"b"
float"f"
double"d"
long"l"
byte"y"
sbyte"Y"
short"h"
ushort"H"
uint"I"
ulong"L"
decimal"m"
char"c"
DateTime"dt"
Guid"g"

Usage

// Compact name round-trip
string compact = TypeNameRegistry.GetCompactTypeName(typeof(List<int>));
// compact == "List<i>"

Type? resolved = TypeNameRegistry.ResolveCompactTypeName("List<i>");
// resolved == typeof(List<int>)

// Full name round-trip
string full = TypeNameRegistry.GetFullTypeName(typeof(MyPlugin.SpecialData));
// full == "MyPlugin.SpecialData, MyPlugin, Version=1.0.0.0, ..."

Type? t = TypeNameRegistry.ResolveFullTypeName(full);

// Clear caches after assembly hot-reload
TypeNameRegistry.ClearCache();

Build docs developers (and LLMs) love