jbtf

package module
v0.2.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 18, 2024 License: MIT Imports: 10 Imported by: 3

README

JSON Binary Transmission Format

Coverage

GLTF inspired JSON schema for embedding arbitrary binaries.

Schema

Standard JSON Serialization

Given we have a basic struct Person.

type Person struct {
    Name string
    Age  int
}

Serializing it's data:

out, _ := jbtf.Marshal(Person{
    Name: "Bob",
    Age:  30,
})
log.Print(string(out))

Produces JSON that embeds the struct inside a data field.

{
    // Data is always present, and takes on the values being serialized
    "data": {
        "Name": "Bob",
        "Age":  30
    }
}

Deserializing is as simple of normal JSON deserialization, with generic support

bob, _ := jbtf.Unmarshal[Person]([]byte(`{"data":{"Name":"Bob","Age":30}}`))
Serializing Binary Data

Let's say we wanted to add a profile picture to the person struct in such a way that we can still load it from a JSON file.

type Person struct {
    Name            string
    Age             int
    ProfilePicture  *jbtf.Png // Make sure it's always a pointer
}

After serializing, we'll notice a few new fields have been added to our JSON document root: buffers and bufferViews.

{
    "buffers": [
        {
            // Total size of this buffer
            "byteLength": 1000,

            // URI of the buffer. Can either encode directly as a string or
            // reference a seperate binary file containing buffer data
            "uri": "[embedded binary data]"
        }
    ],
    // Array of views into buffers defined within this file.
    "bufferViews": [
        {
            "buffer": 0,       // Index of the buffer we're refering to.
            "byteLength": 1000 // Size in bytes of our view
        }
    ],
    // Data is always present, and takes on the values being serialized
    "data": {
        "Name": "Bob",
        "Age":  30,

        // $ at the start of the field indicates this field has had it's data
        // serialized and written into a buffer.
        // 
        // The value of this field is the index of the buffer view that 
        // contains this fields data.
        "$ProfilePicture": 0
    }
}

Custom Serializers

The marshaller and unmarshaller look for types that implement the jbtf.Serializable interface. Let's say we wanted to encode a Person's grade in binary. It's implementation could look something like:

type Grade struct {
    value float32
}

func (g *Grade) Deserialize(in io.Reader) (err error) {
    data := make([]byte, 4)
    _, err = io.ReadFull(in, data)
    g.value = math.Float32frombits(binary.LittleEndian.Uint32(data))
    return
}

func (pss Grade) Serialize(out io.Writer) error {
    bytes := make([]byte, 4)
    binary.LittleEndian.PutUint32(bytes, math.Float32bits(g.value))
    _, err := out.Write(bytes)
    return err
}

Then using the custom serializer is as simple as:

type Person struct {
    Name            string
    Age             int
    ProfilePicture  *jbtf.Png
    Grade           *Grade    // Make sure it's always a pointer
}

Now when serialized, we see a new buffer view appear.

{
    "buffers": [
        {
            "byteLength": 1004,
            "uri": "[embedded binary data]"
        }
    ],
    "bufferViews": [
        // Our custom grade data
        {
            "buffer": 0,    
            "byteLength": 4
        },
        // Profile picture
        {
            "buffer": 0,
            // A byte offset is required if we're not starting from the 
            // begining of the buffer
            "byteOffset": 4,
            "byteLength": 1000
        }
    ],
    "data": {
        "Age":  30,
        "$Grade": 0,
        "Name": "Bob",
        "$ProfilePicture": 1
    }
}

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func BuildBuffer

func BuildBuffer(buf Buffer) *bytes.Reader

func Decode

func Decode[T any](d Decoder, data []byte) (T, error)

func IsNilish

func IsNilish(val any) bool

func Marshal

func Marshal(v any) ([]byte, error)

func ParseJsonUsingBuffers

func ParseJsonUsingBuffers[T any](buffers []Buffer, bufferViews []BufferView, data []byte) (T, error)

func Unmarshal

func Unmarshal[T any](data []byte) (T, error)

Types

type Buffer

type Buffer struct {
	ByteLength int    `json:"byteLength"`    // The length of the buffer in bytes.
	URI        string `json:"uri,omitempty"` // The URI (or IRI) of the buffer.  Relative paths are relative to the current glTF asset.  Instead of referencing an external file, this field **MAY** contain a `data:`-URI.
}

type BufferView

type BufferView struct {
	Buffer     int `json:"buffer"`               // The index of the buffer
	ByteOffset int `json:"byteOffset,omitempty"` // The offset into the buffer in bytes.
	ByteLength int `json:"byteLength"`           // The length of the bufferView in bytes.
}

type Bytes added in v0.2.0

type Bytes struct {
	Data []byte
}

Catch-all helper for serializing arbitrary binary data

func (*Bytes) Deserialize added in v0.2.0

func (pi *Bytes) Deserialize(r io.Reader) (err error)

func (Bytes) Serialize added in v0.2.0

func (pi Bytes) Serialize(w io.Writer) error

type Decoder

type Decoder struct {
	// contains filtered or unexported fields
}

func NewDecoder

func NewDecoder(graphJSON []byte) (Decoder, error)

type Encoder

type Encoder struct {
	// contains filtered or unexported fields
}

func (*Encoder) Marshal

func (e *Encoder) Marshal(v any) ([]byte, error)

func (*Encoder) StartNewBuffer

func (e *Encoder) StartNewBuffer()

func (*Encoder) ToPgtf

func (e *Encoder) ToPgtf(v any) ([]byte, error)

type Png

type Png struct {
	Image image.Image
}

Helper struct for serializing images

func (*Png) Deserialize

func (pi *Png) Deserialize(r io.Reader) (err error)

func (Png) Serialize

func (pi Png) Serialize(w io.Writer) error

type Schema

type Schema[T any] struct {
	Buffers     []Buffer     `json:"buffers,omitempty"`
	BufferViews []BufferView `json:"bufferViews,omitempty"`
	Data        T            `json:"data"`
}

type Serializable

type Serializable interface {
	Deserialize(io.Reader) error
	Serialize(io.Writer) error
}

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL