vamp

package module
v0.6.0 Latest Latest
Warning

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

Go to latest
Published: Aug 22, 2022 License: AGPL-3.0 Imports: 15 Imported by: 3

README

Vampire

Binary Data Serialization

Go Reference

Although it is not zero-copy, Vampire provides "direct access" to values, which means you can navigate down any path in a nested data structure without having to analyze too many other parts that come before the value you are looking for.

This property makes the format accessible – “perviam” in Latin. Just because “Vampire” sounds much cooler the format is called Vampire in the end. But vamp is the package name to Go for because its shorter and still associated with vampires.

What is the point of this property for a serialization format?

Message brokers, queuing systems, and other types of middleware often have to make decisions about the data they manage based on tiny pieces of that data. This is often solved by artificially and redundantly adding the desired information as out-of-band data to the normal payload data. Or one decodes the data to find the relevant parts within the payload. If one chooses the second approach, it is more efficient to have to decode only the relevant parts of the payload.

That was the driving idea for the design of Vampire.

Data Types

TYPE ::= BASIC_TYPE | BYTES_TYPE | ARRAY_TYPE | RECORD_TYPE | LIST_TYPE |
         UNION_TYPE | ANY_TYPE
SIZE ::= 'Size8' | 'Size16' | 'Size32'
  • Basic Types: bool; signed and unsigned integers with 8, 16, 32 and 64 bit; 32-bit and 64-bit float

    BASIC_TYPE ::= 'bool' | 'int8' | 'int16' | 'int32' | 'int64' | 'uint8' |
                   'uint16' | 'uint32' | 'unit64' | 'float32' | 'float64'
    
  • Bytes Type: Byte strings with either 8-, 16- or 32-bit size limits (size in Byte)

    BYTES_TYPE ::= '"' SIZE '"'`
    
  • Array Types: Variable length array with 8-bit, 16-bit and 32-bit length limits. Each element has the same type. Length is part of the array value not the array type. The length of an array must be known before writing an array value.

    ARRAY_TYPE ::= '[' SIZE ' ' TYPE ']'
    
  • Record Types: Fixed number of fields where each field has it's own type. Field names are optional and are not part of record values.

    RECORD_TYPE ::= '{' [ FIELD { ' ' FIELD } ] '}'
    
    FIELD ::= [ FIELD_NAME ':' ] TYPE
    
  • List Types: Unbounded (theoretically) sequence of values of the same type. Final length does not need to be known before writing. A 8-, 16- or 32-bit length fields is provided. If the final length fits, it might be recorded in the list value.

    LIST_TYPE ::= '(' SIZE ' ' TYPE ')'
    
  • Union Types: A tagged union with a predefined set of alternative value types. Tags can have 8-, 16- or 32-bit size.

    UNION_TYPE ::= '<' SIZE ' ' TYPE { '|' TYPE } '>'
    
  • Any Type: Write any Vampire value along with its Vampire type.

    ANY_TYPE ::= 'any'
    

Performance

Full Record Write and Read

Using this Go data structure with Vampire type {Age:int8 Name:"Size8" Owners:[Size8 "Size8"] Male:bool}

type Animal struct {
	Age    int      `vamp:",size=8"`
	Name   string   `vamp:",size=8"`
	Owners []string `vamp:",size=8:8"`
	Male   bool
}

Animal{Age: 4, Name: "Candy", Owners: []string{"Mary", "Joe"}, Male:   true}
Format Encoded Bytes Write&Read-Time / Best
Vampire (8-bit offsets) 22
Vampire (16-bit offsets) 26 100%
Vampire (32-bit offsets) 34
JSON (Go std. lib) 60 233%
JSON (jsoniter) 60 110%
GOB 113 2,130%
CBOR 40 112%
Partial Read Performance

This is a test from the vamp-benchmarks project. It runs on 100,000 randomly generated orders with the structure:

type Order struct {
	CustName string
	CustNum  uint32
	Date     time.Time
	Lines    []OrderLine
}

type OrderLine struct {
	MatName string
	MatNum  uint32
	Count   int
	Price   float64
}

The task is to filter all orders that have at least one order line with the MatNum 0. The test targets Vampire's core property of being able to access individual attributes as directly as possible.

Format File Size real user sys total orders/s
JSON 124,023,274 byte 1.447 s 1.022 s 0.401 s 2.869 s 34,855
vamp 52,374,536 byte 0.220 s 0.056 s 0.163 s 0.438 s 228,311
vamp/JSON 42.23% 15.19% 5.43% 40.70% 15.28% 6.55

JSON timing was measured with Jsoniter. File sizes may vary with new test runs becaus of randomly generated data.

Encoding Format

Unfortunately, the good performance of the format does not come as a pure advantage over other formats. Direct access to parts of a Vampire-encoded dataset only works if many of the components of the data format have a fixed size. For basic types, this works because they are only offered in fixed sizes. However, there is a whole range of basic types, for example integers with 8, 16, 32 and 64 bits. The situation is even more complicated with the abstract data types Array, Record, List and Union. The same applies to the Bytes and the Any type. For all of them, a choice must be made for the size range. It needs some understanding of the structure of Vampire encoding to make a reasonable choice.

In addition, the placement of data with size not known a priori, requires it to be located via an offset. The size of this offset affects the size of the data set that can be stored. The offset size is independent of the used Vampire types and is selected for the actual buffer used for writing and reading. Data written with a certain offset size must also be read with the same offset size.

Documentation

Overview

Package vamp implements the Vampire binary data serialization format for Go.

While Vampire does not provide zero-copy characteristics it gives you "direct access" to values i.e., you can navigate any path down into nested structures without parsing too many other parts that come before the value you are looking for. This feature makes any value directly accessible – “perviam” in Latin. Just because “Vampire” sounds much cooler the format is called Vampire in the end. But vamp is the package name to Go for because its shorter and still associated with vampires.

Type Promotion

When reading and writing data, Vamp supports type promotion between certain types to facilitate the preservation of backwards compatibility.

  • Type promotion between integers is supported if a source type can be stored in a target type without loss. E.g. uint16 can be promoted to int32 but no signed integer type can be promoted to any unsigned integer type.

  • float32 will be promoted to `float64`

For the machine-dependent integers int and uint, it depends on the current value whether it can be read from or written to a Vampire integer. If the current value is within the range of the target, the read or write is successful. Otherwise, it results in a runtime error.

Date and Duration

By default as int64 <-> Unix time with millis.

Example
type Animal struct {
	Age    int      `vamp:"age,size=8"`
	Name   string   `vamp:",size=8"`
	Owners []string `vamp:",size=8:8"`
	Male   bool
}
// Use reflection to get the Vampire type; can be created with API, too
t, _ := TypeOf(Animal{})
// We use a 16-bit offset for the buffers
const BufferOffset = Size16
// Create write buffer with room for a Vampire header
wbuf := NewWriteBuffer(t, BufferOffset, HeaderSize, nil)
// Write the header (incl. buffer's offset size) in front of data
copy(wbuf.AllBytes(), HeaderFor(BufferOffset).Bytes())
// Write a record of type t to the buffer. Value has to match type t.
t.Write(wbuf, Animal{
	Age:    4,
	Name:   "Lassie",
	Owners: []string{"Timmy", "Martin"},
	Male:   false,
})
// How many bytes did we write
fmt.Printf("With header: %d; Value data only: %d\n", len(wbuf.AllBytes()), len(wbuf.Bytes()))
// Now extract the complete buffer, incl. header
data := wbuf.AllBytes()
// Wrap data into a read buffer that expects the header at byte 0
// Reads buffer's offset size from header (We could also directly read from wbuf)
rbuf, _ := NewReadBuffer(t, data, false)
// We need the specific type – record – to select a field
rt := t.(*Record)
// Slice the read buffer to the 3rd field "Owners"
revert := rt.Field(rbuf, 2)
// Read the Owners into a string array
var owners []string
rt.FieldType(2).Read(rbuf, &owners)
// We want to unslice the buffer to return to the complete record
rbuf.Unslice(revert)
// Print what we got from the binary data
fmt.Println(owners)
Output:

With header: 35; Value data only: 31
[Timmy Martin]
Example (Lexer)
rd := bufio.NewReader(strings.NewReader(`<Size8
		Foo:[Size8 "Size8"]
	  | float32
	  | {ID:uint32 Name:"Size16"}
	>`))
fmt.Println(Parse(rd))
Output:

<Size8 Foo:[Size8 "Size8"]|float32|{ID:uint32 Name:"Size16"}> <nil>

Index

Examples

Constants

View Source
const (
	// Version of the implemented Vampire encoding schema
	Version = 0

	// Size of Vampire data header in byte
	HeaderSize = len(Header{})
)
View Source
const (
	// Bytes will be read as string if the bytes are valid UTF-8
	CheckUTF8 bytesReadMode = iota

	// Bytes will be read as []byte
	ReadRaw

	// Bytes will be read as string. It is not checked if bytes are valid UTF-8.
	ReadString
)

Bytes Reading Mode

The bytes mode controls how a Vampire array is unmarshaled when the target type is not determined e.g., read into an *any.

View Source
const (
	// Size8 is a 8-bit size range with values 0…255
	Size8 sizeRange = iota

	// Size16 is a 16-bit size range with values 0…65535
	Size16

	// Size32 is a 32-bit size range with values 0…4294967295
	Size32
)

Size Ranges

Size ranges are used in vamp to define the valid range for buffer offsets, string length and any sort of ranges of size in byte that is used in Vampire encoding.

Variables

View Source
var (
	Bool    boolType
	Int8    int8Type
	Int16   int16Type
	Int32   int32Type
	Int64   int64Type
	Uint8   uint8Type
	Uint16  uint16Type
	Uint32  uint32Type
	Uint64  uint64Type
	Float32 float32Type
	Float64 float64Type
)

Vampire Basic Types

Each <N>Type variable implements Type and represents a Vampire type that corresponds directly to a Go type <n> where <n> is <N> folded to lower case e.g., Bool corresponds to Go's bool type.

Marshaler and Unmarshaler interfaces are not explicitly defined for basic types. To implement user defined (un-)marshaling to or from <N>Type a value has to implement methods that match the following convention:

The marshaler for writing <n> to <N>Type:

interface{ VampTo<N>() (<n>, error) }

The unmarshaler for reading <n> from <N>Type:

interface{ VampFrom<N>(<n>) error }
View Source
var Any anyType
View Source
var IOBytesMode = CheckUTF8

Functions

func ResetTypeBuffer

func ResetTypeBuffer(buf *Buffer, off sizeRange, prefix int)

func TypeName added in v0.4.0

func TypeName(t Type) string

TypeName returns the name attached to a type, if any. Otherwise TypeName returns the empty string.

func ValidName added in v0.6.0

func ValidName(s string) int

func WriteType

func WriteType(buf *Buffer, t Type) error

Types

type Alt

type Alt struct {
	S uint
	V any
}

func (Alt) VampUnionAlt

func (a Alt) VampUnionAlt() (uint, any)

type AnyMarshaler

type AnyMarshaler interface {
	VampAnyType() (Type, any)
}

type Array added in v0.5.0

type Array struct {
	// contains filtered or unexported fields
}
Example
a := []string{"boo", "bar", "baz"}
t, _ := TypeOf(a)
fmt.Println(t)
buf := NewWriteBuffer(t, Size16, 0, nil)
t.Write(buf, a)
var out []string
t.Read(&buf.ReadBuffer, &out)
fmt.Printf("%[1]T=%[1]v\n", out)
Output:

[Size32 "Size16"]
[]string=[boo bar baz]

func NewArray added in v0.5.0

func NewArray(length sizeRange, elem Type) *Array

func NewOptional added in v0.5.0

func NewOptional(elem Type) *Array

NewOptional returns an ArrayType with length of Size8 – the smallest sufficient size range. This is the recommended way to represent optional values.

Example
et := NewBytes(Size8, ReadRaw)
ot := NewOptional(et)
buf := NewWriteBuffer(ot, Size8, 0, nil)
ot.WriteOptOne(buf, "Hello, optional!")
var out string
ok, _ := ot.ReadOpt(&buf.ReadBuffer, &out)
fmt.Println(ok, out)
buf.Reset(ot, Size16, 0)
ot.WriteOptNone(buf)
out = "-"
ok, _ = ot.ReadOpt(&buf.ReadBuffer, &out)
fmt.Println(ok, out)
Output:

true Hello, optional!
false -

func (*Array) DynNo added in v0.5.0

func (t *Array) DynNo() uint

func (*Array) Elem added in v0.5.0

func (t *Array) Elem() Type

func (*Array) Equals added in v0.5.0

func (a *Array) Equals(t Type, names bool) bool

func (*Array) FixSize added in v0.5.0

func (t *Array) FixSize() uint

func (*Array) Hash added in v0.5.0

func (a *Array) Hash(h hash.Hash, names bool)

func (*Array) Index added in v0.5.0

func (t *Array) Index(buf *ReadBuffer, i uint) (revert uint)

func (*Array) Len added in v0.5.0

func (t *Array) Len(buf *ReadBuffer) uint

func (*Array) LenRange added in v0.5.0

func (t *Array) LenRange() sizeRange

func (*Array) Read added in v0.5.0

func (t *Array) Read(buf *ReadBuffer, into any) error

func (*Array) ReadArray added in v0.5.0

func (t *Array) ReadArray(buf *ReadBuffer, ls ArrayUnmarshaler) error

func (*Array) ReadOpt added in v0.5.0

func (t *Array) ReadOpt(buf *ReadBuffer, into any) (ok bool, err error)

func (*Array) String added in v0.5.0

func (t *Array) String() string

func (*Array) VampRecordRead added in v0.5.0

func (t *Array) VampRecordRead(rt *Record, buf *ReadBuffer) error

func (*Array) VampRecordWrite added in v0.5.0

func (t *Array) VampRecordWrite(rt *Record, buf *Buffer) error

func (*Array) VampUnionAlt added in v0.5.0

func (t *Array) VampUnionAlt() (uint, any)

func (*Array) Write added in v0.5.0

func (t *Array) Write(buf *Buffer, ls any) (err error)

func (*Array) WriteArray added in v0.5.0

func (t *Array) WriteArray(buf *Buffer, ls ArrayMarshaler) error

func (*Array) WriteOptNone added in v0.5.0

func (t *Array) WriteOptNone(buf *Buffer) error

func (*Array) WriteOptOne added in v0.5.0

func (t *Array) WriteOptOne(buf *Buffer, value any) error

type ArrayMarshaler

type ArrayMarshaler interface {
	VampArrayLen() uint
	VampArrayWriter(i uint) (any, error)
}

type ArrayUnmarshaler

type ArrayUnmarshaler interface {
	VampArrayResize(l uint) error
	VampArrayReader(i uint) (any, error)
	VampArrayFinish() error
}

type Buffer

type Buffer struct {
	ReadBuffer
}

func NewTypeWriteBuffer

func NewTypeWriteBuffer(off sizeRange, at int, buf []byte) *Buffer

func NewWriteBuffer

func NewWriteBuffer(t Type, off sizeRange, at int, buf []byte) *Buffer

func (*Buffer) Reset

func (b *Buffer) Reset(t Type, off sizeRange, prefix int)

type Bytes added in v0.5.0

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

mode is a vamp but not a Vampire thing (Hash; Equals)

func NewBytes added in v0.5.0

func NewBytes(size sizeRange, mode bytesReadMode) Bytes

func NewString added in v0.5.0

func NewString(size sizeRange) Bytes

func (Bytes) DynNo added in v0.5.0

func (t Bytes) DynNo() uint

func (Bytes) Equals added in v0.5.0

func (s Bytes) Equals(t Type, _ bool) bool

func (Bytes) FixSize added in v0.5.0

func (t Bytes) FixSize() uint

func (Bytes) Hash added in v0.5.0

func (s Bytes) Hash(h hash.Hash, _ bool)

func (Bytes) LenRange added in v0.5.0

func (t Bytes) LenRange() sizeRange

func (Bytes) Read added in v0.5.0

func (t Bytes) Read(buf *ReadBuffer, into any) (err error)

User Defined Unmarshaling

Unmarshaling from byte array:

interface{ VampFromBytes([]byte) error } // must copy its argument

Unmarshaling from string:

interface{ VampFromString(string) error }

func (Bytes) ReadBytes added in v0.5.0

func (t Bytes) ReadBytes(buf *ReadBuffer) []byte

func (Bytes) ReadString added in v0.5.0

func (t Bytes) ReadString(buf *ReadBuffer) string

func (Bytes) String added in v0.5.0

func (t Bytes) String() string

func (*Bytes) VampFromUint8 added in v0.5.0

func (t *Bytes) VampFromUint8(v uint8) error

func (Bytes) VampToUint8 added in v0.5.0

func (t Bytes) VampToUint8() (uint8, error)

func (Bytes) VampUnionAlt added in v0.5.0

func (t Bytes) VampUnionAlt() (uint, any)

func (Bytes) Write added in v0.5.0

func (t Bytes) Write(buf *Buffer, value any) error

User Defined Marshaling

Marshaling to byte array:

interface{ VampToBytes() ([]byte, error) }

Marshaling to string:

interface{ VampToString() (string, error) }

func (Bytes) WriteBytes added in v0.5.0

func (t Bytes) WriteBytes(buf *Buffer, data []byte) error

func (Bytes) WriteString added in v0.5.0

func (t Bytes) WriteString(buf *Buffer, s string) error
type Header [4]byte

Header is the VMP header that can be written to buffers to mark the data to be Vampire encoded and to provide the offsetSize used for the data.

The VMP header is "VMPx" where x encodes the vampire version and the offset size.s

Example
fmt.Println(HeaderFor(Size16))
Output:

Vampire-v0+16bit

func HeaderFor

func HeaderFor(s sizeRange) Header

HeaderFor clapms s to valid range

func ParseHeader

func ParseHeader(mem []byte) (h Header, pos int)

func (Header) Bytes

func (h Header) Bytes() []byte

func (Header) SizeRange

func (h Header) SizeRange() sizeRange

func (Header) String

func (h Header) String() string

func (Header) Version

func (h Header) Version() int

type List added in v0.5.0

type List struct {
	// contains filtered or unexported fields
}
Example
a := []string{"boo", "bar", "baz"}
t := NewList(Size32, NewString(Size16))
fmt.Println(t)
buf := NewWriteBuffer(t, Size16, 0, nil)
t.Write(buf, a)
var out any
t.Read(&buf.ReadBuffer, &out)
fmt.Printf("%[1]T=%[1]v\n", out)
Output:

(Size32 "Size16")
[]interface {}=[boo bar baz]

func NewList added in v0.5.0

func NewList(length sizeRange, elem Type) *List

func (*List) DynNo added in v0.5.0

func (t *List) DynNo() uint

func (*List) Elem added in v0.5.0

func (t *List) Elem() Type

func (*List) Equals added in v0.5.0

func (l *List) Equals(t Type, names bool) bool

func (*List) FixSize added in v0.5.0

func (t *List) FixSize() uint

func (*List) Hash added in v0.5.0

func (a *List) Hash(h hash.Hash, names bool)

func (*List) LenRange added in v0.5.0

func (t *List) LenRange() sizeRange

func (*List) ListLen added in v0.5.0

func (t *List) ListLen(buf *ReadBuffer) (len uint, ok bool)

func (*List) Next added in v0.5.0

func (t *List) Next(buf *ReadBuffer) (revert uint, ok bool)

TODO Test ListType.Next()

func (*List) Read added in v0.5.0

func (t *List) Read(buf *ReadBuffer, into any) error

func (*List) ReadList added in v0.5.0

func (t *List) ReadList(buf *ReadBuffer, into ListUnmarshaler) error

func (*List) ReadStream added in v0.5.0

func (l *List) ReadStream(r io.Reader, offSize sizeRange, buffer []byte) *ReadStream

func (*List) String added in v0.5.0

func (t *List) String() string

func (*List) VampRecordRead added in v0.5.0

func (t *List) VampRecordRead(rt *Record, buf *ReadBuffer) error

func (*List) VampRecordWrite added in v0.5.0

func (t *List) VampRecordWrite(rt *Record, buf *Buffer) error

func (*List) VampUnionAlt added in v0.5.0

func (t *List) VampUnionAlt() (uint, any)

func (*List) Write added in v0.5.0

func (t *List) Write(buf *Buffer, val any) error

func (*List) WriteList added in v0.5.0

func (t *List) WriteList(buf *Buffer, ls ListMarshaler) error

func (*List) WriteStream added in v0.5.0

func (l *List) WriteStream(w io.Writer, offSize sizeRange, buffer []byte) *WriteStream

type ListIterator

type ListIterator interface {
	VampListNext() bool
	VampListGet() any
}

type ListMarshaler

type ListMarshaler interface {
	VampListIter() ListIterator
}

type ListUnmarshaler

type ListUnmarshaler interface {
	VampListReader() (any, error)
	VampListAppend(any) error
}

type Path added in v0.6.0

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

func NewPath added in v0.6.0

func NewPath(t Type, p ...uint) (res Path, err error)

func (Path) Select added in v0.6.0

func (p Path) Select(b *ReadBuffer) (rev uint, err error)

type PathElement added in v0.2.0

type PathElement struct {
	T   Type
	Idx uint
}

type PathError added in v0.2.0

type PathError struct {
	// contains filtered or unexported fields
}
Example
rt := NewRecord(
	NewString(Size16),
	Float64,
	Bool,
)
buf := NewWriteBuffer(rt, Size16, 0, nil)
err := rt.WriteFields(buf, "next fails", "", true)
fmt.Println(err)
Output:

.1:vampire cannot write string as float64

func (PathError) Error added in v0.2.0

func (e PathError) Error() string

func (PathError) Unwrap added in v0.2.0

func (e PathError) Unwrap() error

type ReadBuffer

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

ReadBuffer adapts a Vampire encoded byte array to be used for read-only access. One has to use the specific Type that matches the encoded data to read the data from the buffer.

func NewReadBuffer

func NewReadBuffer(t Type, buf []byte, search bool) (*ReadBuffer, error)

NewReadBufferOffSize wraps buf for read access when the offsetSize is provided by a VMP Header in buf. When search is true NewReadBuffer scans for the first valid VMP header and uses it's offsetSize. Otherwise the VMP header must start at buf[0].

func NewReadBufferOffSize

func NewReadBufferOffSize(t Type, off sizeRange, buf []byte) *ReadBuffer

NewReadBufferOffSize wraps buf for read access when the offsetSize used for the encoded data is known. The first byte of the data of Type t must be buf[0].

func NewTypeReadBuffer

func NewTypeReadBuffer(buf []byte, search bool) (*ReadBuffer, error)

func NewTypeReadBufferOffSize

func NewTypeReadBufferOffSize(off sizeRange, buf []byte) *ReadBuffer

func (*ReadBuffer) AllBytes

func (b *ReadBuffer) AllBytes() []byte

func (*ReadBuffer) Bytes

func (b *ReadBuffer) Bytes() []byte

func (*ReadBuffer) Offset

func (b *ReadBuffer) Offset() sizeRange

func (*ReadBuffer) Unslice

func (b *ReadBuffer) Unslice(revert uint)

type ReadStream added in v0.5.0

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

func (*ReadStream) Buffer added in v0.5.0

func (rs *ReadStream) Buffer() *ReadBuffer

func (*ReadStream) Err added in v0.5.0

func (rs *ReadStream) Err() error

func (*ReadStream) Head added in v0.5.0

func (rs *ReadStream) Head() (length uint, data []byte, error error)

func (*ReadStream) Next added in v0.5.0

func (rs *ReadStream) Next() bool

func (*ReadStream) Read added in v0.5.0

func (rs *ReadStream) Read(into any) error

type Record added in v0.5.0

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

TODO Slice to field

Example
r := struct {
	Name string
	Age  uint8
}{
	Name: "John Doe",
	Age:  44,
}
t, _ := TypeOf(r)
fmt.Println(t)
buf := NewWriteBuffer(t, Size16, 0, nil)
t.Write(buf, r)
var out any
t.Read(&buf.ReadBuffer, &out)
fmt.Printf("%[1]T=%[1]v\n", out)
Output:

{Name:"Size16" Age:uint8}
[]interface {}=[John Doe 44]

func NewRecord added in v0.5.0

func NewRecord(fields ...Type) *Record

func (*Record) DynNo added in v0.5.0

func (t *Record) DynNo() uint

func (*Record) Equals added in v0.5.0

func (r *Record) Equals(t Type, names bool) bool

func (*Record) Field added in v0.5.0

func (t *Record) Field(buf *ReadBuffer, i uint) (revert uint)

func (*Record) FieldName added in v0.5.0

func (t *Record) FieldName(i uint) string

func (*Record) FieldType added in v0.5.0

func (t *Record) FieldType(i uint) Type

func (*Record) FixSize added in v0.5.0

func (t *Record) FixSize() uint

func (*Record) Hash added in v0.5.0

func (r *Record) Hash(h hash.Hash, names bool)

func (*Record) NumField added in v0.5.0

func (t *Record) NumField() uint

func (*Record) Read added in v0.5.0

func (t *Record) Read(buf *ReadBuffer, out any) (err error)

func (*Record) ReadFields added in v0.5.0

func (t *Record) ReadFields(buf *ReadBuffer, outs ...any) error

func (*Record) String added in v0.5.0

func (t *Record) String() string

func (*Record) VampArrayFinish added in v0.5.0

func (t *Record) VampArrayFinish() error

func (*Record) VampArrayLen added in v0.5.0

func (t *Record) VampArrayLen() uint

func (*Record) VampArrayReader added in v0.5.0

func (t *Record) VampArrayReader(i uint) (any, error)

func (*Record) VampArrayResize added in v0.5.0

func (t *Record) VampArrayResize(l uint) error

func (*Record) VampArrayWriter added in v0.5.0

func (t *Record) VampArrayWriter(i uint) (any, error)

func (*Record) VampUnionAlt added in v0.5.0

func (t *Record) VampUnionAlt() (uint, any)

func (*Record) Write added in v0.5.0

func (t *Record) Write(buf *Buffer, values any) error

func (*Record) WriteFields added in v0.5.0

func (t *Record) WriteFields(buf *Buffer, values ...any) error

type RecordMarshaler

type RecordMarshaler interface {
	VampRecordWrite(*Record, *Buffer) error
}

type RecordUnmarshaler

type RecordUnmarshaler interface {
	VampRecordRead(*Record, *ReadBuffer) error
}

type Reflect

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

func DefaultReflect

func DefaultReflect() Reflect

func (Reflect) ArraySize

func (r Reflect) ArraySize(s sizeRange) (res Reflect)

func (Reflect) MustTypeOf added in v0.4.0

func (r Reflect) MustTypeOf(val any) Type

func (Reflect) StringSize

func (r Reflect) StringSize(s sizeRange) Reflect

func (Reflect) TypeOf

func (r Reflect) TypeOf(val any) (Type, error)

type Type

type Type interface {
	FixSize() uint // fix size in byte of the type
	DynNo() uint   // number of dynamic elements of the type

	// Write the value to buffer if its structure matches Type
	Write(b *Buffer, value any) error

	// Read buffers content into argument if its structure matches Type
	Read(b *ReadBuffer, into any) error

	Equals(t Type, names bool) bool
	Hash(h hash.Hash, names bool)

	fmt.Stringer
}

Type is the interface of all Vampire types that are used to define the structure of marshaled data. Types can be created as Array, List, Record or Union form other types. Basic types are booleans, signed and unsigned integers with 8, 16, 32 or 64 bit and float with 32 or 64 bit. The special Bytes types are used to hold any binary data, especially UTF-8 strings. Finally there is the Any type that can hold any Vampire value as a tuple of a value and its type.

func Anonymize added in v0.4.0

func Anonymize(t Type) Type

Anonymize strips all attached names from a type and returns the pure type definition.

func MustNamed added in v0.6.0

func MustNamed(n string, t Type) Type

func MustTypeOf added in v0.4.0

func MustTypeOf(val any) Type

func Named added in v0.4.0

func Named(n string, t Type) (Type, error)

Named attaches a name to a type. Type names are irrelevant for the encoded data end exist for documentation only. Passing a named type to the constructors of record or union types will assign the name to the respective record field or union variant.

func Parse added in v0.6.0

func Parse(rd *bufio.Reader) (typ Type, err error)

func ReadType

func ReadType(buf *ReadBuffer) (t Type, err error)

func TypeOf

func TypeOf(val any) (Type, error)
Example
type animal struct {
	Age    int      `vamp:"age,size=8"`
	Name   string   `vamp:",size=8"`
	Owners []string `vamp:",size=8:8"`
	Male   bool     `vamp:"-"`
}
t, err := TypeOf(animal{})
if err != nil {
	fmt.Println(err)
} else {
	fmt.Println(t.String())
}
Output:

{age:int8 Name:"Size8" Owners:[Size8 "Size8"]}

type Union added in v0.5.0

type Union struct {
	AltReader func(alt uint, into any) (reader any, err error)
	// contains filtered or unexported fields
}
Example
type address struct {
	Street string
	No     string
}
type geocoos struct {
	Lat, Lon float64
}
addrType, _ := TypeOf(address{})
geoType, _ := TypeOf(geocoos{})
placeType := NewUnion(Size8,
	addrType,
	MustNamed("geo", geoType),
)
fmt.Println(placeType)
buf := NewWriteBuffer(placeType, Size16, 0, nil)
placeType.Write(buf, Alt{S: 0, V: address{Street: "Justroad", No: "33a"}})
var out any
placeType.Read(&buf.ReadBuffer, &out)
fmt.Printf("%[1]T=%[1]v\n", out)
buf.Reset(placeType, Size16, 0)
placeType.Write(buf, Alt{S: 1, V: geocoos{Lat: 33.321, Lon: 44.123}})
placeType.Read(&buf.ReadBuffer, &out)
fmt.Printf("%[1]T=%[1]v\n", out)
Output:

<Size8 {Street:"Size16" No:"Size16"}|geo:{Lat:float64 Lon:float64}>
[]interface {}=[Justroad 33a]
[]interface {}=[33.321 44.123]

func NewUnion added in v0.5.0

func NewUnion(altRange sizeRange, alts ...Type) *Union

func (*Union) Alt added in v0.5.0

func (t *Union) Alt(i uint) Type

func (*Union) AltName added in v0.5.0

func (t *Union) AltName(i uint) string

func (*Union) AltRange added in v0.5.0

func (t *Union) AltRange() sizeRange

func (*Union) DynNo added in v0.5.0

func (t *Union) DynNo() uint

func (*Union) Equals added in v0.5.0

func (u *Union) Equals(t Type, names bool) bool

func (*Union) FixSize added in v0.5.0

func (t *Union) FixSize() uint

func (*Union) Hash added in v0.5.0

func (u *Union) Hash(h hash.Hash, names bool)

func (*Union) NumAlts added in v0.5.0

func (t *Union) NumAlts() uint

func (*Union) Read added in v0.5.0

func (t *Union) Read(buf *ReadBuffer, into any) error

func (*Union) ReadAlt added in v0.5.0

func (t *Union) ReadAlt(buf *ReadBuffer, selectVal func(uint) any) (any, error)

func (*Union) String added in v0.5.0

func (t *Union) String() string

func (*Union) VampRecordRead added in v0.5.0

func (t *Union) VampRecordRead(rt *Record, buf *ReadBuffer) error

func (*Union) VampRecordWrite added in v0.5.0

func (t *Union) VampRecordWrite(rt *Record, buf *Buffer) error

func (*Union) VampUnionAlt added in v0.5.0

func (t *Union) VampUnionAlt() (uint, any)

func (*Union) WithAltReader added in v0.5.0

func (t *Union) WithAltReader(f func(uint, any) (any, error)) *Union

func (*Union) Write added in v0.5.0

func (t *Union) Write(buf *Buffer, value any) error

func (*Union) WriteAlt added in v0.5.0

func (t *Union) WriteAlt(buf *Buffer, alt uint, value any) error

type UnionMarshaler

type UnionMarshaler interface {
	VampUnionAlt() (uint, any)
}

type UnionUnmarshaler

type UnionUnmarshaler interface {
	VampUnionReader(alt uint, into any) (any, error)
}

type WriteStream added in v0.5.0

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

func (*WriteStream) Close added in v0.5.0

func (ws *WriteStream) Close() error

func (*WriteStream) Flush added in v0.5.0

func (ws *WriteStream) Flush() error

func (*WriteStream) Write added in v0.5.0

func (ws *WriteStream) Write(elem any) error

func (*WriteStream) WriteLast added in v0.5.0

func (ws *WriteStream) WriteLast(elem any) error

func (*WriteStream) WriteWithNext added in v0.5.0

func (ws *WriteStream) WriteWithNext(elem any) error

Directories

Path Synopsis
cmd
examples

Jump to

Keyboard shortcuts

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