PlainBuffers is a simple code generation library. It allows you to generate data structures described by the data schema.
The idea of the library is similar to FlatBuffers, but PlainBuffers are designed for usage in data oriented designs. Main differences from FlatBuffers:
- PlainBuffers allows you to work with regular structures.
There aren't weird
Mutate
-methods, but there are usual struct fields. But it is still a bit tricky with array accessors (see C# Generated Arrays Limitations). - PlainBuffers doesn't have structure size limitations. FlatBuffers' 64KB limit can cause troubles in some cases.
- PlainBuffers allows you to set default values for structure fields. Use the
WriteDefault
method to write them. - PlainBuffers does an automatic memory layout optimization to reduce paddings.
- PlainBuffers allows you to embed external structures into generated types.
- PlainBuffers doesn't support a lot of FlatBuffers' features like the dynamic memory management, the JSON serialization, unions, etc.
For example, see a sample schema and related generated code.
Currently project supports code generation only for the C# language.
The example of the schema language is listed below.
// This is a commentary
// Only one namespace should be defined in schema
namespace Name.Dot.Separated {
// Base enum type should be defined explicitly
enum SampleEnum : byte {
Foo = 1; // All enum values should be annotated by numbers
Bar = 2;
}
// Flag enums are generated with an optional `flags` modifier
enum SampleFlags : ushort flags {
A = 1;
B = 2;
AB = 3;
C = 4;
}
// Struct definition example
// To set default values you should to call a `WriteDefault` method
struct SampleStruct {
bool FieldA = true;
int FieldB = 42;
SampleEnum FiledC = Foo; // Enums also support default values
// If default value is not defined for enum field,
// the first enum variant will be used in the `WriteDefault` method.
// So, this defeinition equals to the `SampleFlags FiledD = A`
SampleFlags FiledD;
}
// Array definition example
// It will generate struct with all the data stored inplace
array SampleArray SampleStruct[10];
// Array items can have default values too
array IndicesArray int[32] = -1;
// Complex truct example
// Any type declared above can be referenced
struct ComplexStruct {
SampleStruct FieldA;
SampleArray FieldB;
IndicesArray FieldC;
}
// Union example
// All fields have a zero offset
// Union size is big enough to fit the biggest field with a proper alignment
union UnionStruct {
SampleStruct FieldA;
SampleArray FieldB;
IndicesArray FieldC;
}
}
You can use primitive types for struct fields, array item types and as underlying types of enum (integers only).
All primitive types are named same
as in the C# language. But char
, decimal
and reference types are not supported.
Enum values should be annotated by numbers. Logical and shift expressions aren't supported now.
Generated arrays are not absolutely safe. Be careful with references to array items and iterators: ensure that lifetimes of them are shorter then the array lifetime.
Since the 2.0.0 version, array indexers were removed because they can produce defensive copies when the array accessed by readonly reference.
Instead of them you should use RefAt
and RefReadonlyAt
extension methods depending on access type.
To get iterators you should use extension methods RefIter
and RefReadonlyIter
.
See usage examples in tests.
PlainBuffers library provides the CSharpUnityCodeGenerator
class that uses UnsafeUtility
instead of Span<T>
.
- Write tests for compiler internal code (currently only core library and generated code are covered by tests now)
- Add code generation for languages other then the C#