Skip to content

tinywasm/json

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

75 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

JSON

A single, platform-agnostic JSON codec for Go that optimizes WebAssembly binary size by using zero reflection. It relies on fmt.Fielder for struct encoding/decoding, which is typically generated by ormc.

Index

Architecture

  • Zero Reflection: Uses type switches and fmt.Fielder 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.
  • Fielder-Only: Only types implementing fmt.Fielder can be directly encoded or decoded.

Usage

Structs

Structs MUST implement fmt.Fielder to be supported. This is normally handled by generating code with ormc.

package main

import (
    "github.com/tinywasm/fmt"
    "github.com/tinywasm/json"
)

// User implements fmt.Fielder (typically via ormc)
type User struct {
    Name string
}

func (u *User) Schema() []fmt.Field {
    return []fmt.Field{{Name: "name", Type: fmt.FieldText}}
}
func (u *User) Pointers() []any { return []any{&u.Name} }

func main() {
    u := User{Name: "Alice"}

    var out string
    if err := json.Encode(&u, &out); err != nil {
        panic(err)
    }
    // out: {"name":"Alice"}

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

    // Recommended: Explicit validation (if result implements fmt.Validator or uses fmt.ValidateFields)
    // if err := fmt.ValidateFields('c', &result); err != nil {
    //     panic(err)
    // }
}

API

Encode(data fmt.Fielder, output any) error

Serializes a Fielder to JSON. JSON keys are always taken from field.Name. If field.OmitEmpty is true, the field is skipped if its value is zero.

  • data: Must implement fmt.Fielder.
  • output: *[]byte, *string, or io.Writer.

Decode(input any, data fmt.Fielder) error

Parses JSON into a Fielder.

  • input: []byte, string, or io.Reader.
  • data: Must implement fmt.Fielder.

Supported Types and Limitations

To maintain a minimal footprint and zero reflection, tinywasm/json has specific support and constraints:

Supported Field Types

The encoder and decoder directly support the following fmt.FieldType mappings:

Go Type fmt.FieldType JSON Equivalent
string FieldText string
int, int64, etc. FieldInt number
float64, float32 FieldFloat number
bool FieldBool boolean
[]byte FieldBlob string (escaped)
[]int FieldIntSlice array of numbers
Fielder FieldStruct object (nested)

Limitations

  • No Reflection: Generic types like map[string]any, []any, or arbitrary structs NOT implementing fmt.Fielder are NOT supported.
  • Root Object Only: Both Encode and Decode expect a fmt.Fielder as the root element. You cannot directly encode/decode a bare string or number as a standalone JSON value.
  • No Maps: Key-value pairs are only supported via struct fields described in the Schema().
  • Simplified Arrays: Currently, only []int is supported as a slice type. Other slice types like []string or []float64 are not yet supported.
  • No Custom Marshaling: Standard interfaces like json.Marshaler or json.Unmarshaler are ignored.
  • Fielder Contract: Structs must return pointers to all fields in the same order as the schema via Pointers().

Benchmarks

tinywasm/json is 77% smaller than encoding/json in WASM (~27 KB vs ~119 KB) and zero-reflect, eliminating reflection overhead and heavy dependencies.

Benchmark tinywasm/json encoding/json
Encode 285 ns/op 276 ns/op
Decode 320 ns/op 1078 ns/op

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


Contributing

License

See LICENSE for details.

About

A lightweight JSON wrapper for Go that optimizes WebAssembly binary size. It automatically switches between the standard encoding/json for backends and the browser's native JSON API (via syscall/js) for WASM builds.

Resources

License

Stars

Watchers

Forks

Sponsor this project

 

Packages

 
 
 

Contributors