SkillAgentSearch skills...

Bon

A serialization library for the Beef programming language. Designed to easily serialize and deserialize data structures.

Install / Use

/learn @EinScott/Bon
About this skill

Quality Score

0/100

Category

Design

Supported Platforms

Universal

README

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

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.
  • default Zero value Value is explicitly zero.
  • null Null 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

View on GitHub
GitHub Stars14
CategoryDesign
Updated5d ago
Forks4

Languages

Beef

Security Score

95/100

Audited on Mar 26, 2026

No findings