yamly

package module
v0.1.1 Latest Latest
Warning

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

Go to latest
Published: Sep 24, 2023 License: Apache-2.0 Imports: 3 Imported by: 4

README

yamly GitHub Workflow Status (with event) Codecov Go Report Card

Package yamly provides a new way for YAML marshalling/unmarshalling, using code generation instead of runtime reflection. In this terms yamly is similar to easyjson. However, currently yamly is more proof of concept than really competitive and production-ready library.

Usage

Install
go get github.com/KSpaceer/yamly && go install github.com/KSpaceer/yamly/...@latest
Run
yamlygen -type <target type> <package directory>

This command will generate a _yamly.go file with marshalling and unmarshalling functions for target type from package directory.

Like easyjson and ffjson, yamly code generation invokes go run on a temporary file, therefore a full Go build environment is required.

Options

Flags:
  -build-tags string
    	build tags to add to generated file
  -disallow-unknown-fields
    	return error if unknown field appeared in yaml
  -encode-pointer-receiver
    	use pointer receiver in encode methods
  -engine string
    	used parser engine for generated code (default "goyaml")
  -inline-embedded
    	inline embedded fields into YAML mapping
  -omitempty
    	omit empty fields by default
  -output string
    	name of generated file
  -type string
    	target type to generated marshaling methods

Struct tags

Currently yamly supports two struct tags:

  • 'omitempty' - marshal field only in case it is not empty.
  • 'inline' - inline the field, i.e. treat all field's nested as if they were the part of host struct.

Engines

Yamly uses different parsing engines to generate code (i.e. engine is somewhat of 'backend' of marshalling). At this time yamly supports two engines:

  • yayamls (Yet another YAML serializer) - self-made engine aiming to full coverage of YAML specification.
  • goyaml - engine using go-yaml as base.

Performance

yamly is still raw and has pretty mediocre performance. With yayamls engine it is 2x times slower than go-yaml package, and with goyaml engine it only compares (not surpasses) the mentioned package. In case of yayamls it is okay because yayamls has full coverage as main goal, but in case of goyaml it only brings overhead because of additional layer over parsing and marshalling, not mentioning difficulties of code generation.

The best way to resolve this problem is to implement new engine with direct access to lexing and tokenizing processes, which builds no AST.

Documentation

Overview

Package yamly contains main interfaces and errors used for code generation and import.

Index

Constants

This section is empty.

Variables

View Source
var (
	// ErrEndOfStream indicates an end of YAML document (stream) during decoding.
	ErrEndOfStream = errors.New("end of YAML stream")
	// ErrDenied error indicates that Decoder called method was denied because current AST node
	// can't be represented as desired value.
	ErrDenied = (*denyError)(nil)
	// ErrUnmarshalerImplementation is used by engines to indicate that type does not
	// implement any unmarshalling interface in runtime.
	ErrUnmarshalerImplementation = errors.New("interface type is not supported: expect only interface{} " +
		"(any), yamly.Unmarshaler or engine-specific unmarshalling interfaces")
)
View Source
var ErrMarshalerImplementation = errors.New("interface type is not supported: expect only interface{} " +
	"(any), yamly.Marshaler or engine-specific marshalling interfaces")

ErrMarshalerImplementation is used by engines to indicate that type does not implement any marshalling interface in runtime.

Functions

func DenyError

func DenyError(err error) error

DenyError marks given error as ErrDenied error.

Types

type CollectionState

type CollectionState interface {
	// Size returns elements amount in the complex node.
	Size() int
	// HasUnprocessedItems shows if Decoder has not processed any element of the complex node yet.
	HasUnprocessedItems() bool
}

CollectionState serves as a current state of complex node (e.g. sequence) for Decoder.

type Decoder

type Decoder interface {
	// TryNull returns a boolean value indicating if current node is null node.
	// If it is null, proceeds to the next node.
	TryNull() bool

	// Integer extracts an integer value of given bit size from current text node.
	// If current node is not a text node or its value does not represent integer,
	// a ErrDenied error is stored in Decoder.
	Integer(bitSize int) int64

	// Unsigned extracts an unsigned integer value of given bit size from current text node.
	// If current node is not a text node or its value does not represent unsigned integer,
	// a ErrDenied error is stored in Decoder.
	Unsigned(bitSize int) uint64

	// Boolean extracts a boolean value of given bit size from current text node.
	// If current node is not a text node or its value does not represent boolean,
	// a ErrDenied error is stored in Decoder.
	Boolean() bool

	// Float extracts a float value of given bit size from current text node.
	// If current node is not a text node or its value does not represent float,
	// a ErrDenied error is stored in Decoder.
	Float(bitSize int) float64

	// String extracts a string value of given bit size from current text node.
	// If current node is not a text node, a ErrDenied error is stored in Decoder.
	String() string

	// Timestamp extracts a time.Time value of given bit size from current text node.
	// If current node is not a text node or its value does not represent date,
	// a ErrDenied error is stored in Decoder.
	Timestamp() time.Time

	// Sequence expects a sequence node in AST and returns a CollectionState associated with it.
	// If Decoder meets unexpected node (e.g. text or mapping), a ErrDenied error is stored in Decoder.
	Sequence() CollectionState

	// Mapping expects a mapping node in AST and returns a CollectionState associated with it.
	// If Decoder meets unexpected node (e.g. text or sequence), a ErrDenied error is stored in Decoder.
	Mapping() CollectionState

	// Any converts current subtree into Go value and returns it.
	Any() any

	// Raw serializes and returns current subtree as bytes.
	Raw() []byte

	// Skip skips current subtree and proceeds to the next.
	Skip()

	// Error returns a stored error.
	Error() error

	// AddError allows to add custom error to Decoder.
	AddError(err error)
}

Decoder is used to extract values from YAML AST.

type Encoder

type Encoder interface {
	Inserter

	// EncodeToString encodes the AST builded with Inserter methods as a string.
	EncodeToString() (string, error)
	// EncodeToBytes encodes the AST builded with Inserter methods as a byte slice.
	EncodeToBytes() ([]byte, error)
	// EncodeTo encodes the AST builded with Inserter methods and writes the serialized data into given io.Writer.
	EncodeTo(dst io.Writer) error
}

Encoder allows inserting values into an YAML AST and encoding builded AST as string or bytes.

func NewEncoder

func NewEncoder[T any](builder TreeBuilder[T], writer TreeWriter[T]) Encoder

NewEncoder returns an Encoder used to construct and serialize YAML AST tree of given type.

type ExtendedDecoder

type ExtendedDecoder[T any] interface {
	Decoder

	// Node returns current subtree.
	Node() T
}

ExtendedDecoder is used to extend Decoder interface with engine-specific methods

type Inserter

type Inserter interface {
	// InsertInteger inserts an integer into AST as text node
	InsertInteger(int64)

	// InsertUnsigned inserts an unsigned integer into AST as text node.
	InsertUnsigned(uint64)

	// InsertBoolean inserts a boolean value into AST as text node.
	InsertBoolean(bool)

	// InsertFloat inserts a float value into AST as text node.
	InsertFloat(float64)

	// InsertString inserts a string value into AST as text node.
	InsertString(string)

	// InsertTimestamp inserts a time.Time value into AST as text node.
	InsertTimestamp(time.Time)

	// InsertNull inserts a null node into AST.
	InsertNull()

	// StartSequence creates a sequence node in AST.
	// Until EndSequence is called, every inserted node will be inserted as sequence element.
	StartSequence()
	// EndSequence finishes a sequence created before with StartSequence.
	// If current node is not a sequence (i.e. StartSequence was not called or nested mapping/sequence is not finished),
	// an error is added to inserter.
	EndSequence()

	// StartMapping creates a mapping node in AST.
	// Until EndMapping is called, every odd inserted node will be inserted as mapping entry key
	// and every even inserted node will be inserted as mapping entry value.
	StartMapping()
	// EndMapping finished a mapping created before with StartMapping.
	// If current node is not a sequence (i.e. StartMapping was not called or nested mapping/sequence is not finished),
	// or there is a pending mapping entry (with created key and absent value),
	// an error is added to inserter
	EndMapping()

	// InsertRaw inserts given raw bytes in YAML as subtree into AST.
	// Also, it accepts an error to make it comfortable to call Marshaler.MarshalYAML to provide arguments.
	InsertRaw([]byte, error)
	// InsertRawText inserts given raw bytes as text node into AST.
	// Also, it accepts an error to make it comfortable to call encoding.TextMarshaler methods to provide arguments.
	InsertRawText([]byte, error)
}

Inserter allows inserting values into an YAML AST. If any error occurs during insertion, further calls are no-op.

type MarshalerYamly

type MarshalerYamly interface {
	MarshalYamly(Inserter)
}

MarshalerYamly interface can be implemented to customize type's behaviour when being marshaled into a YAML document inserting a subtree into builded AST.

type TreeBuilder

type TreeBuilder[T any] interface {
	Inserter
	// Result returns the AST builded with Inserter methods.
	Result() (T, error)
}

TreeBuilder allows inserting values into a generic YAML AST and returning result AST.

type TreeWriter

type TreeWriter[T any] interface {
	// WriteTo serializes given tree and writes serialized bytes into given io.Writer.
	WriteTo(dst io.Writer, tree T) error
	// WriteString serializes given tree as string.
	WriteString(tree T) (string, error)
	// WriteBytes serializes given tree as bytes.
	WriteBytes(tree T) ([]byte, error)
}

TreeWriter serializes given generic YAML AST as string or bytes.

type UnknownFieldError

type UnknownFieldError struct {
	Field string
}

UnknownFieldError is used to indicate unknown field for struct when unmarshaler is generated with unknown field disallowing.

func (*UnknownFieldError) Error

func (ufe *UnknownFieldError) Error() string

func (*UnknownFieldError) Is

func (ufe *UnknownFieldError) Is(err error) bool

type UnmarshalerYamly

type UnmarshalerYamly interface {
	UnmarshalYamly(Decoder)
}

UnmarshalerYamly interface can be implemented to customize type's behaviour when being unmarshaled from YAML document using Decoder.

Directories

Path Synopsis
cmd
engines
pkg/schema
Package schema contains function to derive and convert types from YAML source.
Package schema contains function to derive and convert types from YAML source.
goyaml Module
yayamls Module
Package generator contains code generator for YAML marshalling and unmarshalling methods.
Package generator contains code generator for YAML marshalling and unmarshalling methods.
bootstrap
Package bootstrap contains generator for bootstrap main with actual generating with generator.Generator
Package bootstrap contains generator for bootstrap main with actual generating with generator.Generator
parser
Package parser contains parser for package name and path.
Package parser contains parser for package name and path.

Jump to

Keyboard shortcuts

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