Categorygithub.com/segmentio/objconv
modulepackage
1.0.1
Repository: https://github.com/segmentio/objconv.git
Documentation: pkg.go.dev

# README

objconv CircleCI Go Report Card GoDoc

This Go package provides the implementation of high performance encoder and decoders for JSON-like object representations.

The top-level package exposes the generic types and algorithms for encoding and decoding values, while each sub-package implements the parser and emitters for specific types.

Breaking changes introduced in #18

The Encoder type used to have methods exposed to encode specific types for optimization purposes. The generic Encode method has been optimized to make those other methods obsolete and they were therefore removed.

Compatibility with the standard library

The sub-packages providing implementation for specific formats also expose APIs that mirror those of the standard library to make it easy to integrate with the objconv package. However there are a couple of differences that need to be taken in consideration:

  • Encoder and Decoder types are not exposed in the objconv sub-packages, instead the types from the top-level package are used. For example, variables declared with the json.Encoder type would have to be replaced with objconv.Encoder.

  • Interfaces like json.Marshaler or json.Unmarshaler are not supported. However the encoding.TextMarshaler and encoding.TextUnmarshaler interfaces are.

Encoder

The package exposes a generic encoder API that let's the program serialize native values into various formats.

Here's an example of how to serialize a structure to JSON:

package main

import (
    "os"

    "github.com/segmentio/objconv/json"
)

func main() {
    e := json.NewEncoder(os.Stdout)
    e.Encode(struct{ Hello string }{"World"})
}
$ go run ./example.go
{"Hello":"World"}

Note that this code is fully compatible with the standard encoding/json package.

Decoder

Here's an example of how to use a JSON decoder:

package main

import (
    "fmt"
    "os"

    "github.com/segmentio/objconv/json"
)

func main() {
    v := struct{ Message string }{}

    d := json.NewDecoder(os.Stdin)
    d.Decode(&v)

    fmt.Println(v.Message)
}
$ echo '{ "Message": "Hello World!" }' | go run ./example.go
Hello World!

Streaming

One of the interesting features of the objconv package is the ability to read and write streams of data. This has several advantages in terms of memory usage and latency when passing data from service to service.
The package exposes the StreamEncoder and StreamDecoder types for this purpose.

For example the JSON stream encoder and decoder can produce a JSON array as a stream where data are produced and consumed on the fly as they become available, here's an example:

package main

import (
    "io"

    "github.com/segmentio/objconv/json"
)

func main() {
     r, w := io.Pipe()

    go func() {
        defer w.Close()

        e := json.NewStreamEncoder(w)
        defer e.Close()

        // Produce values to the JSON stream.
        for i := 0; i != 1000; i++ {
            e.Encode(i)
        }
    }()

    d := json.NewStreamDecoder(r)

    // Consume values from the JSON stream.
    var v int

    for d.Decode(&v) == nil {
        // v => {0..999}
        // ...
    }
}

Stream decoders are capable of reading values from either arrays or single values, this is very convenient when an program cannot predict the structure of the stream. If the actual data representation is not an array the stream decoder will simply behave like a normal decoder and produce a single value.

Encoding and decoding custom types

To override the default encoder and decoder behaviors a type may implement the ValueEncoder or ValueDecoder interface. The method on these interfaces are called to customize the default behavior.

This can prove very useful to represent slice of pairs as maps for example:

type KV struct {
    K string
    V interface{}
}

type M []KV

// Implement the ValueEncoder interface to provide a custom encoding.
func (m M) EncodeValue(e objconv.Encoder) error {
    i := 0
    return e.EncodeMap(len(m), func(k objconv.Encoder, v objconv.Encoder) (err error) {
        if err = k.Encode(m[i].K); err != nil {
            return
        }
        if err = v.Encode(m[i].V); err != nil {
            return
        }
        i++
        return
    })
}

Mime Types

The objconv package exposes APIs for registering codecs for specific mime types. When an objconv package for a specific format is imported it registers itself on the global registry to be later referred by name.

import (
    "bytes"

    "github.com/segmentio/objconv"
    _ "github.com/segmentio/objconv/json" // registers the JSON codec
)

func main() {
    // Lookup the JSON codec.
    jsonCodec, ok := objconv.Lookup("application/json")

    if !ok {
        panic("unreachable")
    }

    // Create a new encoder from the codec.
    b := &bytes.Buffer{}
    e := jsonCodec.NewEncoder(b)

    // ...
}

# Packages

Package adapters installs all adapters from its subpackages into the objconv package.
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author

# Functions

AdapterOf returns the adapter for typ, setting ok to true if one was found, false otherwise.
Codecs returns a map of all codecs registered in the global registry.
Install adds an adapter for typ.
Lookup returns the codec associated with mimetype, ok is set to true or false based on whether a codec was found.
NewDecoder returns a decoder object that uses p, will panic if p is nil.
NewEncoder returns a new encoder that outputs values to e.
NewStreamDecoder returns a new stream decoder that takes input from p.
NewStreamEncoder returns a new stream encoder that outputs to e.
NewValueEmitter returns a pointer to a new ValueEmitter object.
NewValueParser creates a new parser that exposes the value v.
Register adds a codec for a mimetype to the global registry.
Unregister removes the codec for a mimetype from the global registry.

# Constants

No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author

# Variables

Discard is a special emitter that outputs nothing and simply discards the values.
End is expected to be returned to indicate that a function has completed its work, this is usually employed in generic algorithms.

# Structs

An Adapter is a pair of an encoder and a decoder function that can be installed on the package to support new types.
A Codec is a factory for encoder and decoders that work on byte streams.
A Decoder implements the algorithms for building data structures from their serialized forms.
An Encoder implements the high-level encoding algorithm that inspect encoded values and drive the use of an Emitter to create a serialized representation of the data.
A Registry associates mime types to codecs.
StreamDecoder decodes values in a streaming fashion, allowing an array to be consumed without loading it fully in memory.
A StreamEncoder encodes and writes a stream of values to an output stream.
ValueEmitter is a special kind of emitter, instead of serializing the values it receives it builds an in-memory representation of the data.
ValueParser is parser that uses "natural" in-memory representation of data structures.

# Interfaces

The Emitter interface must be implemented by types that provide encoding of a specific format (like json, resp, ...).
The Parser interface must be implemented by types that provide decoding of a specific format (like json, resp, ...).
The PrettyEmitter interface may be implemented by emitters supporting a more human-friendlly format.
ValueDecoder is the interface that can be implemented by types that wish to provide their own decoding algorithms.
ValueEncoder is the interface that can be implemented by types that wish to provide their own encoding algorithms.

# Type aliases

Type is an enumeration that represent all the base types supported by the emitters and parsers.
ValueDecoderFunc allows the use of regular functions or methods as value decoders.
ValueEncoderFunc allows the use of regular functions or methods as value encoders.