Bon
A serialization library for the Beef programming language. Designed to easily serialize and deserialize data structures.
Install / Use
/learn @EinScott/BonREADME
bon
Bon is a serialization library for the Beef programming language and is designed to easily serialize and deserialize beef data structures.
Basics
Bon is reflection based. (De-) Serialization of a value is done in one call to Bon.Serialize or Bon.Deserialize.
Any (properly marked) structure can be passed into these calls to produce a valid result or, in the case of Deserialization, a precise error (not a crash!).
For example, assuming that all types used below use the build settings or the [BonTarget] attribute to include reflection data for them and all fields set below are public or explicitly included, this structure results in the following serialized bon output.
let structure = new State() {
currentMode = .Battle(5),
gameRules = .FriendlyFire | .RandomDrops,
playerInfo = new List<PlayerInfo>() {
.() {
gold = 231,
level = 2,
dead = false
},
.() {
gold = 0,
level = 1,
dead = true
},
default
},
partyName = new String("ChaosCrew")
};
gBonEnv.serializeFlags |= .Verbose; // Output is formatted for editing & readability
let serialized = Bon.Serialize(structure, .. scope String());
Content of serialized:
{
gameRules = .FriendlyFire|.RandomDrops,
partyName = "ChaosCrew",
currentMode = .Battle{
stage = 5
},
playerInfo = [
{
level = 2,
gold = 231
},
{
level = 1,
dead = true
},
{}
]
}
The output omits default values if possible (the deserializer will try to default unmentioned values accordingly). This, among other behaviors, is configurable just like with the .Verbose flag set above to produce a formatted and more extensive output. Bon's configuration is contained in a BonEnvironment object, that is passed into every call. By default, the global environment gBonEnv is used.
For an extensive overview of bon's capabilities, see Documentation and Tests.
Documentation
- Serialization
- Deserialization
- Supported types
- Errors
- Syntax
- Type setup
- Bon environment
- Extension
- Integrated usage
- Preprocessor defines
Serialization
Any properly set up (and supported) value can be passed into Serialize.
int i = 15;
Bon.Serialize(i, outStr); // outStr: "15"
Deserialization
Any value passed into Deserialize will be set to the state defined in the bon string, with a few restrictions. Bon will allocate appropriate instances into empty references but can not null used references. Ideally, references point to instances of the right type or are cleared beforehand.
int i = ?;
Try!(Bon.Deserialize(ref i, "15"));
SomeClass c = null;
Try!(Bon.Deserialize(ref c, "{member=120}"));
Nulling references
Bon should never leak object references. When getting an error from this, it is recommended that you clear structures manually or always ignore the field. If bon is always deserializing into empty structures, this case will never occur.
Alternatively, when nulling references due to them not being specified in the bon string (for example old saves where something didn't exist in the structure yet), putting [BonKeepUnlessSet] will leave the field's value as is in those cases. See keeping field values for all options.
Supported types
- Primitives (integers, floats, booleans, characters - and typed primitives)
- Enums & Enum unions
- String & StringView (though StringView requires some setup)
- List
- Dictionary
- Nullable structs
- Custom structs/classes (if marked properly, may be processed through type handlers)
Pointers
Pointers are not supported. Pointer fields can be excluded by putting [BonIgnore] on them.
Errors
Serializing does not produce errors and always outputs a valid bon entry. With .Verbose configured for serialize in the used bon environment, the serializer might output comments with "warnings", for example when a type doesn't have reflection info.
Deserializing might error when encountering syntax errors or types that are not properly set up for use with bon - in the way that the parsed string demands (for example, polymorphism usage). These are, by default, printed to the console (or debug output for tests). The call returns .Err after encountering an error.
BON ERROR: Unterminated string. (line 1)
> "eg\"
> ^
BON ERROR: Integer is out of range. (line 1)
> 299
> ^
> On type: int8
BON ERROR: Field access not allowed. (line 1)
> {i=5,f=1,str="oh hello",dont=8}
> ^
> On type: Bon.Tests.SomeThings
BON ERROR: Cannot handle pointer values. (line 1)
> {}
> ^
> On type: uint8*
Printing of errors is disabled in non-DEBUG configurations and can be forced off by defining BON_NO_PRINT or on by defining BON_PRINT in the workspace settings. Optionally, defining BON_PROVIDE_ERROR_MESSAGE always makes bon call the Bon.onDeserializeError event with the error message before returning (in case you want to want to properly report it).
Syntax
Comments
Beef/C style comments are supported. // single line comments, and /* */ multiline comments (even nested ones).
File-level
Every file is a list of values. Most commonly, a file is only made up of one element/value. These elements are independent of each other and are each serialized or deserialized in one call. For example:
2,
{
name = "Gustav",
profession = .Cook
}
Would be serialized in two calls. The first one consumes that element from the resulting BonContext (which strings can implicitly convert to). This allows for some more loose structures and conditional parsing of files. In this case, we check the file version to decide on the layout to expect.
int version = ?;
CharacterInfo char = null;
var context = Try!(Bon.Deserialize(ref version, bonString));
if (version == 1)
{
CharacterInfoLegacy old = null;
context = Try!(Bon.Deserialize(ref old, context));
char = old.ToNewFormat(.. new .());
}
else context = Bon.Deserialize(ref char, context);
Debug.Assert(context.GetEntryCount() == 0); // No more entries left in the file
Similarly, multiple Bon.Serialize(...) calls can be performed on the same string to produce a file with multiple entries.
Special values
?Irrelevant value: Means default or ignored value based on field's or type's configuration. See keeping field values.defaultZero value Value is explicitly zero.nullNull reference: Only valid on reference types. Reference is explicitly null.
Integer numbers
Integers are range-checked and can be denoted in decimal, hexadecimal, binary or octal notation. The u suffix is valid on unsigned numbers, the l suffix is recognized but ignored.
246,
2456u,
-34L,
0xBF43,
0b1011,
0o270
Floating point numbers
Floating point numbers can be denoted in decimal. The f and d suffix is valid but ignored.
1,
-1.59f,
.3,
1.57e-3,
1.352e-3d,
Infinity
Chars
Chars start and end with ' and their contents are size- and range-checked. Escape sequences \', \", \\, \0, \a, \b, \f, \n, \r, \t, \v, \xFF, \u{10FFFF} are supported (based on the char size).
'a',
'\t',
'\x09'
Enums
Enums can be represented by integer numbers or the type's named cases. Named cases are preceded by a ., multiple cases can be combined with |.
24,
.ACase,
.Tree | .Bench | 0b1100,
0xF | 0x80 | .Choice,
.SHIFT | .STRG | 'q' // For char enums, also allow char literals
Strings
Strings are single-line and start and end with a (non-escaped) ". The @ prefix marks verbatim strings. The escape sequences listed in char are valid in strings as well.
"hello!",
"My name is \"Grek\", nice to meet you!",
@"C:\Users\Grek\AppData\Roaming\",
"What's this: \u{30A1}? Don't know..."
Object bodies
Object bodies are enclosed by object brackets {}. They contain a sequence of <fieldIdentifier>=<value> entries.
{
dontCareArray = default,
name = "dave",
gameEntity = null,
stats = {
strength = 17,
dexterity = 10,
wisdom = 14,
charisma = 6
}
}
Array bodies
Array bodies are enclosed by array brackets []. They contain a list of <value> entries. Array bodies might be preceded by array sizers <>. Array sizers denot
Related Skills
diffs
344.1kUse the diffs tool to produce real, shareable diffs (viewer URL, file artifact, or both) instead of manual edit summaries.
clearshot
Structured screenshot analysis for UI implementation and critique. Analyzes every UI screenshot with a 5×5 spatial grid, full element inventory, and design system extraction — facts and taste together, every time. Escalates to full implementation blueprint when building. Trigger on any digital interface image file (png, jpg, gif, webp — websites, apps, dashboards, mockups, wireframes) or commands like 'analyse this screenshot,' 'rebuild this,' 'match this design,' 'clone this.' Skip for non-UI images (photos, memes, charts) unless the user explicitly wants to build a UI from them. Does NOT trigger on HTML source code, CSS, SVGs, or any code pasted as text.
openpencil
2.0kThe world's first open-source AI-native vector design tool and the first to feature concurrent Agent Teams. Design-as-Code. Turn prompts into UI directly on the live canvas. A modern alternative to Pencil.
HappyColorBlend
HappyColorBlendVibe Project Guidelines Project Overview HappyColorBlendVibe is a Figma plugin for color palette generation with advanced tint/shade blending capabilities. It allows designers to
