json

package module
v0.5.14 Latest Latest
Warning

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

Go to latest
Published: Jul 18, 2026 License: MIT Imports: 5 Imported by: 2

README

tinywasm/json

A single, platform-agnostic JSON codec for Go that optimizes WebAssembly binary size by using zero reflection. It relies on model.Encodable and model.Decodable for struct encoding/decoding.

Architecture

  • Zero Reflection: Uses type switches and visitor pattern instead of the reflect package.
  • Platform-Agnostic: Identical behavior on all platforms (WASM, Linux, macOS, etc.).
  • TinyGo Compatible: Optimized for minimal binary size and memory usage.
  • 0-Allocation: Hot path is allocation-free (reusing fmt.Conv buffers and pooling writers/readers).
  • Typed Codec: Only types implementing model.Encodable/model.Decodable can be directly encoded or decoded.

Usage

Structs — define, don't declare

You do not hand-write a struct with EncodeFields/DecodeFields yourself. You define the model's fields once as a model.Definition, and ormc generates the struct plus its Schema()/Pointers()/EncodeFields()/ DecodeFields() into a *_orm.go file. Running tinywasm (the framework) does this for you automatically: it watches every model.go and regenerates the matching *_orm.go on save — you never run ormc by hand in normal development, and you never edit the generated file.

model.go (source of truth — this is what you write):

package app

import "github.com/tinywasm/model"

var LogEntryModel = model.Definition{
    Name: "log_entry",
    Fields: []model.Field{
        {Name: "id", Type: model.FieldText},
        {Name: "content", Type: model.FieldText},
        {Name: "type", Type: model.FieldInt},
    },
}

model_orm.go (generated — never edit; regenerated on every model.go save):

// DO NOT EDIT. generated by github.com/tinywasm/ormc

package app

import "github.com/tinywasm/model"

type LogEntry struct {
    Id      string
    Content string
    Type    int64
}

func (m *LogEntry) Schema() []model.Field { return LogEntryModel.Fields }
func (m *LogEntry) Pointers() []any       { return []any{&m.Id, &m.Content, &m.Type} }
func (m *LogEntry) IsNil() bool           { return m == nil }

func (m *LogEntry) EncodeFields(w model.FieldWriter) {
    w.String("id", m.Id)
    w.String("content", m.Content)
    w.Int("type", m.Type)
}

func (m *LogEntry) DecodeFields(r model.FieldReader) {
    if v, ok := r.String("id"); ok { m.Id = v }
    if v, ok := r.String("content"); ok { m.Content = v }
    if v, ok := r.Int("type"); ok { m.Type = v }
}

You just call json against the generated type:

import "github.com/tinywasm/json"

entry := LogEntry{Id: "1", Content: "started", Type: 0}

var out string
if err := json.Encode(&entry, &out); err != nil {
    panic(err)
}
// out: {"id":"1","content":"started","type":0}

var result LogEntry
if err := json.Decode(out, &result); err != nil {
    panic(err)
}

(Real example, mechanically simplified from app/model.go / app/model_orm.go in this monorepo.)

json.Encode/json.Decode only require model.Encodable (EncodeFields/IsNil) and model.Decodable (DecodeFields/IsNil) — the two methods shown above. model.Fielder/Pointers()/Schema() (the rest of what ormc generates) are a separate contract used only by the SQL/form layers; json never touches them. This means a small internal type that is NOT a model.Definition-backed model — never persisted, never shown in a form — may implement EncodeFields/DecodeFields/IsNil by hand instead of going through ormc; see json/tests/raw_test.go's rawFielder for a minimal hand-written example. That is the exception, not the pattern to reach for by default — reach for model.Definition + ormc first.

API

Encode(data model.Encodable, output any) error

Serializes to JSON. If data is a collection of objects, it is encoded as a JSON array [...]; otherwise as an object {...}.

  • data: model.Encodable{...} or [...]
  • output: *[]byte, *string, or io.Writer.
Decode(input any, data model.Decodable) error

Parses JSON into data.

  • input: []byte, string, or io.Reader.
  • data: model.Decodable → expects {...} or [...]

Benchmarks

tinywasm/json is 83% smaller than encoding/json in WASM (51 KB vs 270 KB, 20 KB vs 118 KB gzipped), zero-reflect, and 0-allocation on the serialization hot path.

Benchmark tinywasm/json encoding/json Faster Δ allocs
Encode 604 ns/op 799 ns/op +24% 0
Decode 1503 ns/op 3098 ns/op +51% -3

See full results and analysis in benchmarks/README.md.


Contributing

License

See LICENSE for details.

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Decode added in v0.1.0

func Decode(input any, data model.Decodable) error

Decode parses JSON into a Decodable. input: []byte | string | io.Reader.

func Encode added in v0.1.0

func Encode(data model.Encodable, output any) error

Encode serializes an Encodable to JSON. output: *[]byte | *string | io.Writer.

Types

This section is empty.

Directories

Path Synopsis
benchmarks
clients/stdlib command
web command

Jump to

Keyboard shortcuts

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