Files
Ryan a08663c7b9 Version bump 2.7.0 (#5399)
# Description of Changes

<!-- Please describe your change, mention any related tickets, and so on
here. -->

- Bumps version to 2.7.0

# API and ABI breaking changes

<!-- If this is an API or ABI breaking change, please apply the
corresponding GitHub label. -->

None

# Expected complexity level and risk

- 1 - this is just a version bump

<!--
How complicated do you think these changes are? Grade on a scale from 1
to 5,
where 1 is a trivial change, and 5 is a deep-reaching and complex
change.

This complexity rating applies not only to the complexity apparent in
the diff,
but also to its interactions with existing and future code.

If you answered more than a 2, explain what is complex about the PR,
and what other components it interacts with in potentially concerning
ways. -->

# Testing

<!-- Describe any testing you've done, and any testing you'd like your
reviewers to do,
so that you're confident that all the changes work as expected! -->

- [x] Version number is correct (`2.7.0`)
- [x] BSL license file has been updated with the new date and version
number
2026-06-22 04:08:56 +00:00
..
2024-12-16 21:49:42 +00:00

⚠️ Internal Project ⚠️

This project is intended for internal use only. It is not stable and may change without notice.

Internal documentation

This project contains Roslyn incremental source generators that augment types with methods for self-describing and serialization. It relies on the BSATN.Runtime library in the generated code.

This project provides [SpacetimeDB.Type]. This attribute makes types self-describing, allowing them to automatically register their structure with SpacetimeDB. It also generates serialization code to the BSATN format. Any C# type annotated with [SpacetimeDB.Type] can be used as a table column or reducer argument.

Any [SpacetimeDB.Type] must be marked partial to allow the generated code to add new functionality.

[SpacetimeDB.Type] also supports emulation of tagged enums in C#. For that, the struct needs to inherit a marker interface SpacetimeDB.TaggedEnum<Variants> where Variants is a named tuple of all possible variants, e.g.:

[SpacetimeDB.Type]
partial record Option<T> : SpacetimeDB.TaggedEnum<(T Some, Unit None)>;

will generate inherited records Option.Some(T Some_) and Option.None(Unit None_). It allows you to use tagged enums in C# in a similar way to Rust enums by leveraging C# pattern-matching on any instance of Option<T>.

What is generated

See ../Codegen.Tests/fixtures/client/snapshots for examples of the generated code. ../Codegen.Tests/fixtures/server/snapshots also has examples, those filenames starting with Type#. In addition, in any project using this library, you can set <EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles> in the <PropertyGroup> of your .csproj to see exactly what code is geing generated for your project.

[SpacetimeDB.Type] automatically generates correct Equals, GetHashCode, and ToString methods for the type. It also generates serialization code.

Any [SpacetimeDB.Type] will have an auto-generated member struct named BSATN. This struct is zero-sized and implements the interface SpacetimeDB.BSATN.IReadWrite<T> interface. This is used to serialize and deserialize elements of the struct.

[SpacetimeDB.Type]
partial struct Banana {
    public int Freshness;
    public int LengthMeters;
}

void Example(System.IO.BinaryReader reader, System.IO.BinaryWriter writer) {
    Banana.BSATN serializer = new();
    Banana banana1 = serializer.Read(reader); // read a BSATN-encoded Banana from the reader.
    Banana banana2 = serializer.Read(reader);
    Console.Log($"bananas: {banana1} {banana2}");
    Console.Log($"equal?: {banana1.Equals(banana2)}");
    serializer.write(writer, banana2); // write a BSATN-encoded Banana to the writer.
    serializer.write(writer, banana1);
}

Since Banana.BSATN takes up no space in memory, allocating one is free. We use this pattern because the C# versions we target don't support static interface methods.

[SpacetimeDB.Type]s that do not inherit from SpacetimeDB.TaggedEnum implement an additional interface, IStructuralReadWrite. This allows them to be read without using a serializer. (This is not possible for TaggedEnums because their concrete type is not known before deserialization.)

void Example(System.IO.BinaryReader reader, System.IO.BinaryWriter writer) {
    Banana banana = new(); // has default field values.
    banana.ReadFields(reader); // now it is initialized.
    banana.WriteFields(writer); // and we can write it out directly as well.
}

The IReadWrite interface has an additional method, AlgebraicType GetAlgebraicType(). This returns a description of the type that is used during module initialization; see ../Runtime for more information.

Testing

The testing for this project lives in two places.

  • ../Codegen.Tests contains snapshot-based tests. These verify that the generated code looks as expected and allow it to be reviewed more easily.
  • Randomized runtime tests live in ../BSATN.Runtime.Tests. These tests randomly fuzz the generated serializers for a variety of types.