> ⚠️ **DEPRECATED** — This wiki is no longer maintained. The current documentation lives in
> [`/documentation`](https://github.com/joeedh/STRUCT/tree/master/documentation).
> See the equivalent page: [documentation/Intro-and-Examples.md](https://github.com/joeedh/STRUCT/blob/master/documentation/Intro-and-Examples.md).

# Introduction

[STRUCT](@STRUCT) is a ProtoBuf-like binary serialization system for JavaScript.  Developed for production use, it minimizes both storage space and object creation (the source of virtually all performance problems in JS).  The original use case was implementing undo, which required a fast method of writing the application state into a memory file.

STRUCT differs from ProtoBuf in that it is tied to JS and that it [compiles its equivalent to .proto files](https://developers.google.com/protocol-buffers/docs/proto#simple) at runtime.  In fact, these "files" are usually embedded in the JS code.

# Direct serialization of objects

Unlike ProtoBuf, STRUCT is designed to serialize and deserialize existing JS object types.  It does not generate object classes for you, it uses the ones you already have.  This avoids a great deal of duplicate object creation, which in large applications can lead to significant performance loss.

# Example

Here's a simple example of using STRUCT:

    class SomeClass {
      constructor(an_object_reference)
           this.a = 0;
           this.b = "a string";
           this.c = an_object_reference;
           this.d = new SomeOtherClass();
           this.e = true;
           this.f = 1.23432;
        }
        
        /*
          Optional method to allocate a new instance.

          reader is the exact same continuation that's 
          passed to loadSTRUCT, try not to use it
          (it's necassary for typed arrays to work 
           properly with nstructjs).

          Note that the return value's .loadSTRUCT method 
          is still called, though the
          call to reader inside of it will be ignored
         */
        static newSTRUCT(reader) {
            return new SomeClass();
        }

        loadSTRUCT(reader) {
          reader(this);
          //if you wanted to include parent class's loadSTRUCT, 
          //call super.loadSTRUCT here *after reader has been called*
          
           //turn integer id back into object reference
           ret.c = lookup_object_from_uuid(ret.c);
        }
    }

    SomeClass.STRUCT = '
      mymodule.SomeClass {
        a : int;
        b : string;
        c : int | obj.c.uuid;
        d : SomeOtherClass;
        e : bool;
        f : float;
      }
    ';

    nstructjs.manager.add_class(SomeClass);




Let's look at the STRUCT script:

`        "mymodule.SomeClass {",`

This has the name of our class as well as a module prefix (which is optional).  The next three lines are self-explanatory; things get interesting on line four:

`        "    c : int | obj.c.uuid;", //store an integer ID for this.c instead of actual object`

The code right of | is a "helper script", a line of JS code that tells STRUCT how to serialize a given object method.  In this case, we want to save the integer UUID of a referenced object (note that 'obj' represents the a SomeClass instance's 'this').  

We can still save the whole object if we want, so long as it's constructor is registered with STRUCT):

`        "    d : SomeOtherClass;", //store full object`

# Arrays

If we want to save an array, we can use:

`       "  some_array : array(SomeType);"`

What if we want to transform the items in the array?  STRUCT provides a simple map mechanism for that:

`       " some_array : array(item, SomeType) | [do something with item];"`

The helper JS code will be called once for each item in some_array, rather than once.  If, however, you want the helper code to only be executed once (for the whole array), simply emit the first argument:

`       "  some_array : array(SomeType) | [do something with obj.some_array];"`

# Abstract Classes

What if you don't know the exact class of a property?  In that case, you use the abstract keyword:

`       "  some_property : abstract(SomeBaseClass);"`

This tells STRUCT that some_property may be a subclass of SomeBaseClass.  Since STRUCT is designed to be very compact, objects are normally saved without any sort of type information; the abstract keyword simply tells STRUCT to write a type ID before some_property.
