oscript

package
v0.1.1 Latest Latest
Warning

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

Go to latest
Published: Jan 16, 2020 License: MIT Imports: 17 Imported by: 0

Documentation

Overview

Example (CustomMarshalOscript)
package main

import (
	"fmt"
	"log"
	"strings"

	"github.com/itcomusic/ot/pkg/oscript"
)

type Animal int

const (
	Unknown Animal = iota
	Gopher
	Zebra
)

func (a *Animal) UnmarshalOscript(b []byte) error {
	var s string

	if err := oscript.Unmarshal(b, &s); err != nil {
		return err
	}

	switch strings.ToLower(s) {
	default:
		*a = Unknown

	case "gopher":
		*a = Gopher

	case "zebra":
		*a = Zebra
	}
	return nil
}

func (a Animal) MarshalOscript() ([]byte, error) {
	var s string
	switch a {
	default:
		s = "unknown"

	case Gopher:
		s = "gopher"

	case Zebra:
		s = "zebra"
	}
	return oscript.Marshal(s)
}

func main() {
	blob := `{'gopher','armadillo','zebra','unknown','gopher','bee','gopher','zebra'}`
	var zoo []Animal

	if err := oscript.Unmarshal([]byte(blob), &zoo); err != nil {
		log.Fatal(err)
	}

	census := make(map[Animal]int)
	for _, animal := range zoo {
		census[animal]++
	}

	fmt.Printf("Zoo Census:\n* Gophers: %d\n* Zebras:  %d\n* Unknown: %d\n",
		census[Gopher], census[Zebra], census[Unknown])
}
Output:

Zoo Census:
* Gophers: 3
* Zebras:  2
* Unknown: 3

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func Compact

func Compact(dst *bytes.Buffer, src []byte) error

Compact appends to dst the oscript-encoded src with insignificant space characters elided.

func Marshal

func Marshal(v interface{}) ([]byte, error)

The encoding of each struct field can be customized by the format string stored under the "oscript" key in the struct field's tag. The format string gives the name of the field, possibly followed by a comma-separated list of options. The name may be empty in order to specify options without overriding the default field name.

The "omitempty" option specifies that the field should be omitted from the encoding if the field has an empty value, defined as false, 0, a nil pointer, a nil interface value, and any empty array, slice, map, or string.

As a special case, if the field tag is "-", the field is always omitted. Note that a field with name "-" can still be generated using the tag "-,".

Anonymous struct fields are usually marshaled as if their inner exported fields were fields in the outer struct, subject to the usual Go visibility rules amended as described in the next paragraph. An anonymous struct field with a name given in its Oscript tag is treated as having that name, rather than being anonymous. An anonymous struct field of interface type is treated the same as having that type as its name, rather than being anonymous.

The Go visibility rules for struct fields are amended for Oscript when deciding which field to marshal or unmarshal. If there are multiple fields at the same level, and that level is the least nested (and would therefore be the nesting level selected by the usual Go rules), the following extra rules apply:

1) Of those fields, if any are Oscript-tagged, only tagged fields are considered, even if there are multiple untagged fields that would otherwise conflict.

2) If there is exactly one field (tagged or not according to the first rule), that is selected.

3) Otherwise there are multiple fields, and all are ignored; no error occurs.

Map values encode as oscript objects: A<1,?,'key'=value>. The map's key type must either be a string, an integer type, or implement encoding.TextMarshaler.

  • string keys are used directly
  • encoding.TextMarshalers are marshaled
  • integer keys are converted to strings

Pointer values encode as the value pointed to. A nil pointer encodes as the undefined Oscript value.

Interface values encode as the value contained in the interface. A nil interface value encodes as the undefined Oscript value.

Channel, complex, and function values cannot be encoded in oscript. Attempting to encode such a value causes Marshal to return an UnsupportedTypeError.

Oscript cannot represent cyclic data structures and Marshal does not handle them. Passing cyclic structures to Marshal will result in an infinite recursion.

Example
package main

import (
	"fmt"
	"os"

	"github.com/itcomusic/ot/pkg/oscript"
)

func main() {
	type ColorGroup struct {
		ID     int
		Name   string
		Colors []string
	}
	group := ColorGroup{
		ID:     1,
		Name:   "Reds",
		Colors: []string{"Crimson", "Red", "Ruby", "Maroon"},
	}
	b, err := oscript.Marshal(group)
	if err != nil {
		fmt.Println("error:", err)
	}
	os.Stdout.Write(b)
}
Output:

A<1,?,'ID'=1,'Name'='Reds','Colors'={'Crimson','Red','Ruby','Maroon'}>

func Unmarshal

func Unmarshal(data []byte, v interface{}) error

The oscript undefined value unmarshals into an interface, map, pointer, or slice by setting that Go value to nil. Because undefined is often used in oscript to mean `not present' unmarshaling a Oscript undefined into any other Go type has no effect on the value and produces no error.

When unmarshaling quoted strings, invalid UTF-8 or invalid UTF-16 surrogate pairs are not treated as an error. Instead, they are replaced by the Unicode replacement character U+FFFD.

Example
package main

import (
	"fmt"

	"github.com/itcomusic/ot/pkg/oscript"
)

func main() {
	var oscriptBlob = []byte(`{
	A<1,?,'Name'= 'Platypus', 'Order'= 'Monotremata'>,
	A<1,?,'Name'= 'Quoll',    'Order'= 'Dasyuromorphia'>
}`)
	type Animal struct {
		Name  string
		Order string
	}

	var animals []Animal
	err := oscript.Unmarshal(oscriptBlob, &animals)

	if err != nil {
		fmt.Println("error:", err)
	}
	fmt.Printf("%+v", animals)
}
Output:

[{Name:Platypus Order:Monotremata} {Name:Quoll Order:Dasyuromorphia}]

func Valid

func Valid(data []byte) bool

Valid reports whether data is a valid Oscript encoding.

Types

type Buffer

type Buffer interface {
	WriteString(s string) (int, error)
	WriteStringValue(s string)
	WriteByte(b byte) error
	WriteEncode(v interface{})
}

Buffer is the interface implemented by internal encodeState.

type Decoder

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

A Decoder reads and decodes Oscript values from an input stream.

Example

This example uses a Decoder to decode a stream of distinct Oscript values.

package main

import (
	"fmt"
	"io"
	"log"
	"strings"

	"github.com/itcomusic/ot/pkg/oscript"
)

func main() {
	const oscriptStream = `
	A<1,?,'Name'= 'Ed', 'Text'= 'Knock knock.'>
 	A<1,?,'Name'= 'Sam', 'Text'= 'Who\'s there?'>
	A<1,?,'Name'= 'Ed', 'Text'= 'Go fmt.'>
	A<1,?,'Name'= 'Sam', 'Text'= 'Go fmt who?'>
	A<1,?,'Name'= 'Ed', 'Text'= 'Go fmt yourself!'>
`
	type Message struct {
		Name, Text string
	}
	dec := oscript.NewDecoder(strings.NewReader(oscriptStream))

	for {
		var m Message
		if err := dec.Decode(&m); err == io.EOF {
			break

		} else if err != nil {
			log.Fatal(err)
		}
		fmt.Printf("%s: %s\n", m.Name, m.Text)
	}

}
Output:

Ed: Knock knock.
Sam: Who's there?
Ed: Go fmt.
Sam: Go fmt who?
Ed: Go fmt yourself!

func NewDecoder

func NewDecoder(r io.Reader) *Decoder

NewDecoder returns a new decoder that reads from r.

The decoder introduces its own buffering and may read data from r beyond the oscript values requested.

func (*Decoder) Buffered

func (dec *Decoder) Buffered() io.Reader

Buffered returns a reader of the data remaining in the Decoder's buffer. The reader is valid until the next call to Decode.

func (*Decoder) Decode

func (dec *Decoder) Decode(v interface{}) error

Decode reads the next Oscript-encoded value from its input and stores it in the value pointed to by v.

See the documentation for Unmarshal for details about the conversion of Oscript into a Go value.

Example (Stream)

This example uses a Decoder to decode a streaming array of Oscript objects.

package main

import (
	"fmt"
	"log"
	"strings"

	"github.com/itcomusic/ot/pkg/oscript"
)

func main() {
	const oscriptStream = `
	{
		A<1,?,'Name'= 'Ed', 'Text'= 'Knock knock.'>,
		A<1,?,'Name'= 'Sam', 'Text'= 'Who\'s there?'>,
		A<1,?,'Name'= 'Ed', 'Text'= 'Go fmt.'>,
		A<1,?,'Name'= 'Sam', 'Text'= 'Go fmt who?'>,
		A<1,?,'Name'= 'Ed', 'Text'= 'Go fmt yourself!'>
	}
`
	type Message struct {
		Name, Text string
	}

	dec := oscript.NewDecoder(strings.NewReader(oscriptStream))
	// read open bracket
	t, err := dec.Token()

	if err != nil {
		log.Fatal(err)
	}

	fmt.Printf("%T: %v\n", t, t)
	// while the array contains values
	for dec.More() {
		var m Message
		// decode an array value (Message)
		err := dec.Decode(&m)
		if err != nil {
			log.Fatal(err)
		}
		fmt.Printf("%v: %v\n", m.Name, m.Text)
	}

	// read closing bracket
	t, err = dec.Token()

	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("%T: %v\n", t, t)

}
Output:

oscript.Delim: {
Ed: Knock knock.
Sam: Who's there?
Ed: Go fmt.
Sam: Go fmt who?
Ed: Go fmt yourself!
oscript.Delim: }

func (*Decoder) DisallowUnknownFields

func (dec *Decoder) DisallowUnknownFields()

DisallowUnknownFields causes the Decoder to return an error when the destination is a struct and the input contains object keys which do not match any non-ignored, exported fields in the destination.

func (*Decoder) More

func (dec *Decoder) More() bool

More reports whether there is another element in the current array or object being parsed.

func (*Decoder) Token

func (dec *Decoder) Token() (Token, error)

Token returns the next Oscript token in the input stream. At the end of the input stream, Token returns nil, io.EOF.

Token guarantees that the delimiters A<1,? > { } it returns are properly nested and matched: if Token encounters an unexpected delimiter in the input, it will return an error.

The input stream consists of basic Oscript values—bool, string, number, and undefined—along with delimiters A<1,? > { } of type Delim to mark the start and end of arrays and objects. Commas and equally are elided.

Example

This example uses a Decoder to decode a stream of distinct Oscript values.

package main

import (
	"fmt"
	"io"
	"log"
	"strings"

	"github.com/itcomusic/ot/pkg/oscript"
)

func main() {
	const oscriptStream = `
	A<1,?,'Message'= 'Hello', 'Array'= {1, 2, 3}, 'Undefined'= ?, 'Number'= G1.234>
`
	dec := oscript.NewDecoder(strings.NewReader(oscriptStream))

	for {
		t, err := dec.Token()
		if err == io.EOF {
			break
		}

		if err != nil {
			log.Fatal(err)
		}
		fmt.Printf("%T: %v", t, t)

		if dec.More() {
			fmt.Printf(" (more)")
		}
		fmt.Printf("\n")
	}
}
Output:

oscript.Delim: A (more)
string: Message (more)
string: Hello (more)
string: Array (more)
oscript.Delim: { (more)
int64: 1 (more)
int64: 2 (more)
int64: 3
oscript.Delim: } (more)
string: Undefined (more)
<nil>: <nil> (more)
string: Number (more)
float64: 1.234
oscript.Delim: >

type Delim

type Delim rune

A Delim is a Oscript array or object delimiter, one of { } A or >.

func (Delim) String

func (d Delim) String() string

type Encoder

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

An Encoder writes Oscript values to an output stream.

func NewEncoder

func NewEncoder(w io.Writer) *Encoder

NewEncoder returns a new encoder that writes to w.

func (*Encoder) EnableEncodeNL

func (enc *Encoder) EnableEncodeNL()

EnableEncodeNL enables newline after call Encode.

func (*Encoder) Encode

func (enc *Encoder) Encode(v interface{}) error

Encode writes the Oscript encoding of v to the stream, followed by a newline character.

See the documentation for Marshal for details about the conversion of Go values to Oscript.

type Error

type Error int

Error is a error string.

func (Error) Error

func (e Error) Error() string

Error returns error message.

func (Error) MarshalOscript

func (e Error) MarshalOscript() ([]byte, error)

MarshalOscript implements the oscript.Marshaler interface.

func (*Error) UnmarshalOscript

func (e *Error) UnmarshalOscript(data []byte) error

UnmarshalOscript implements the oscript.Unmarshaler interface.

type InvalidUnmarshalError

type InvalidUnmarshalError struct {
	Type reflect.Type
}

An InvalidUnmarshalError describes an invalid argument passed to Unmarshal. (The argument to Unmarshal must be a non-nil pointer.)

func (*InvalidUnmarshalError) Error

func (e *InvalidUnmarshalError) Error() string

type M

type M map[string]interface{}

M is a convenient alias for a map[string]interface{} map, useful for short define For instance: script.M{"key1": 1, "key2": true}

There's no special handling for this type in addition to what's done anyway for an equivalent map type.

type Marshaler

type Marshaler interface {
	MarshalOscript() ([]byte, error)
}

Marshaler is the interface implemented by types that can marshal themselves into valid oscript.

type MarshalerBuf

type MarshalerBuf interface {
	MarshalOscriptBuf(buf Buffer) error
}

MarshalerBuf is the interface implemented by types that can marshal themselves and does not require addition allocation as a Marshaller for returning []byte.

type MarshalerError

type MarshalerError struct {
	Type reflect.Type
	Err  error
}

func (*MarshalerError) Error

func (e *MarshalerError) Error() string

type SDOName

type SDOName struct{}

type SyntaxError

type SyntaxError struct {
	Offset int64 // error occurred after reading Offset bytes
	// contains filtered or unexported fields
}

A SyntaxError is a description of a Oscript syntax error.

func (*SyntaxError) Error

func (e *SyntaxError) Error() string

type Token

type Token interface{}

A Token holds a value of one of these types:

Delim, for the four Oscript delimiters A > { }
bool, for Oscript booleans
number, for Oscript integers
float64, for Oscript reals
string, for Oscript string literals
nil, for Oscript ?

type UnmarshalTypeError

type UnmarshalTypeError struct {
	Value  string       // description of Oscript value - "bool", "array", "number -5"
	Type   reflect.Type // type of Go value it could not be assigned to
	Offset int64        // error occurred after reading Offset bytes
	Struct string       // name of the struct type containing the field
	Field  string       // name of the field holding the Go value
}

An UnmarshalTypeError describes a Oscript value that was not appropriate for a value of a specific Go type.

func (*UnmarshalTypeError) Error

func (e *UnmarshalTypeError) Error() string

type Unmarshaler

type Unmarshaler interface {
	UnmarshalOscript([]byte) error
}

Unmarshaler is the interface implemented by types that can unmarshal a Oscript description of themselves. The input can be assumed to be a valid encoding of a Oscript value. UnmarshalOscript must copy the Oscript data if it wishes to retain the data after returning.

By convention, to approximate the behavior of Unmarshal itself, Unmarshalers implement UnmarshalOscript([]byte("?")) as a no-op.

type UnsupportedTypeError

type UnsupportedTypeError struct {
	Type reflect.Type
}

An UnsupportedTypeError is returned by Marshal when attempting to encode an unsupported value type.

func (*UnsupportedTypeError) Error

func (e *UnsupportedTypeError) Error() string

type UnsupportedValueError

type UnsupportedValueError struct {
	Value reflect.Value
	Str   string
}

An UnsupportedValueError is returned by Marshal when attempting to encode an unsupported value.

func (*UnsupportedValueError) Error

func (e *UnsupportedValueError) Error() string

Jump to

Keyboard shortcuts

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