Skip to content

Golang implementation of Y3 Codec, a fast than real-time TLV based binary codec with low CPU usage

License

Notifications You must be signed in to change notification settings

yomorun/y3-codec-golang

Repository files navigation

đź“š VERSION: draft-02

⛳️ STATE: WIP

🇨🇳 简体中文 🇬🇧 English

Y3

FOSSA Status

Y3 is the golang implementation of Y3 Codec, which describe a fast and low CPU binding data encoder/decoder focus on edge computing and streaming processing.

See the explainer for more info, more about the ways to combine with YoMo.

Y3 Codec

See Y3 Codec SPEC

Test

go test ./...

Use

go get -u github.com/yomorun/y3-codec-golang

Examples

Encode examples

package main

import (
	"fmt"
	y3 "github.com/yomorun/y3-codec-golang"
)

func main() {
	// if we want to repesent `var obj = &foo{ID: -1, bar: &bar{Name: "C"}}` 
	// in Y3-Codec:

	// 0x81 -> node
	var foo = y3.NewNodePacketEncoder(0x01)

	// 0x02 -> foo.ID=-11
	var yp1 = y3.NewPrimitivePacketEncoder(0x02)
	yp1.SetInt32Value(-1)
	foo.AddPrimitivePacket(yp1)

	// 0x83 -> &bar{}
	var bar = y3.NewNodePacketEncoder(0x03)

	// 0x04 -> bar.Name="C"
	var yp2 = y3.NewPrimitivePacketEncoder(0x04)
	yp2.SetStringValue("C")
	bar.AddPrimitivePacket(yp2)
	
	// -> foo.bar=&bar
	foo.AddNodePacket(bar)

	fmt.Printf("res=%#v", foo.Encode()) // res=[]byte{0x81, 0x08, 0x02, 0x01, 0x7F, 0x83, 0x03, 0x04, 0x01, 0x43}
}

Decode examples 1: decode a primitive packet

package main

import (
	"fmt"
	y3 "github.com/yomorun/y3-codec-golang"
)

func main() {
	fmt.Println(">> Parsing [0x0A, 0x01, 0x7F], which like Key-Value format = 0x0A: 127")
	buf := []byte{0x0A, 0x01, 0x7F}
	res, _, err := y3.DecodePrimitivePacket(buf)
	v1, err := res.ToUInt32()
	if err != nil {
		panic(err)
	}

	fmt.Printf("Tag Key=[%#X], Value=%v\n", res.SeqID(), v1)
}

Decode examples 2: decode a node packet

package main

import (
	"fmt"
	y3 "github.com/yomorun/y3-codec-golang"
)

func main() {
	fmt.Println(">> Parsing [0x84, 0x06, 0x0A, 0x01, 0x7F, 0x0B, 0x01, 0x43] EQUALS JSON= 0x84: { 0x0A: -1, 0x0B: 'C' }")
	buf := []byte{0x84, 0x06, 0x0A, 0x01, 0x7F, 0x0B, 0x01, 0x43}
	res, _, err := y3.DecodeNodePacket(buf)
	v1 := res.PrimitivePackets[0]

	p1, err := v1.ToInt32()
	if err != nil {
		panic(err)
	}
	fmt.Printf("Tag Key=[%#X.%#X], Value=%v\n", res.SeqID(), v1.SeqID(), p1)

	v2 := res.PrimitivePackets[1]

	p2, err := v2.ToUTF8String()
	if err != nil {
		panic(err)
	}

	fmt.Printf("Tag Key=[%#X.%#X], Value=%v\n", res.SeqID(), v2.SeqID(), p2)
}

More examples in /examples/

Types

Y3 implements the YoMo Codec protocol and supports the following Golang data types and provides Hight-Level wrappers.

int32
// encode
var data int32 = 123
var prim = y3.NewPrimitivePacketEncoder(0x01)
prim.SetInt32Value(data)
buf := prim.Encode()
// decode
res, _, _, _ := y3.DecodePrimitivePacket(buf)
val, _ := res.ToInt32()
fmt.Printf("val=%d", val)
uint32
var data uint32 = 123
var prim = y3.NewPrimitivePacketEncoder(0x01)
prim.SetUInt32Value(data)
buf := prim.Encode()
// decode
res, _, _, _ := y3.DecodePrimitivePacket(buf)
val, _ := res.ToUInt32()
fmt.Printf("val=%d", val)  
int64
// encode
var data int64 = 123
var prim = y3.NewPrimitivePacketEncoder(0x01)
prim.SetInt64Value(data)
buf := prim.Encode()
// decode
res, _, _, _ := y3.DecodePrimitivePacket(buf)
val, _ := res.ToInt64()
fmt.Printf("val=%d", val)  
uint64
// encode
var data uint64 = 123
var prim = y3.NewPrimitivePacketEncoder(0x01)
prim.SetUInt64Value(data)
buf := prim.Encode()
// decode
res, _, _, _ := y3.DecodePrimitivePacket(buf)
val, _ := res.ToUInt64()
fmt.Printf("val=%d", val) 
float32
// encode
var data float32 = 1.23
var prim = y3.NewPrimitivePacketEncoder(0x01)
prim.SetFloat32Value(data)
buf := prim.Encode()
// decode
res, _, _, _ := y3.DecodePrimitivePacket(buf)
val, _ := res.ToFloat32()
fmt.Printf("val=%f", val) 
float64
// encode
var data float64 = 1.23
var prim = y3.NewPrimitivePacketEncoder(0x01)
prim.SetFloat64Value(data)
buf := prim.Encode()
// decode
res, _, _, _ := y3.DecodePrimitivePacket(buf)
val, _ := res.ToFloat64()
fmt.Printf("val=%f", val)  
bool
// encode
var data bool = true
var prim = y3.NewPrimitivePacketEncoder(0x01)
prim.SetBoolValue(data)
buf := prim.Encode()
// decode
res, _, _, _ := y3.DecodePrimitivePacket(buf)
val, _ := res.ToBool()
fmt.Printf("val=%v", val)  
string
// encode
var data string = "abc"
var prim = y3.NewPrimitivePacketEncoder(0x01)
prim.SetStringValue(data)
buf := prim.Encode()
// decode
res, _, _, _ := y3.DecodePrimitivePacket(buf)
val, _ := res.ToUTF8String()
fmt.Printf("val=%s", val) 
int32 slice
// encode
data := []int32{123, 456}
var node = y3.NewNodeSlicePacketEncoder(0x10)
if out, ok := utils.ToInt64Slice(data); ok {
	for _, v := range out {
		var item = y3.NewPrimitivePacketEncoder(0x00)
		item.SetInt32Value(int32(v.(int64)))
		node.AddPrimitivePacket(item)
	}
}
buf := node.Encode()
// decode
packet, _, _ := y3.DecodeNodePacket(buf)
result := make([]int32, 0)
for _, p := range packet.PrimitivePackets {
	v, _ := p.ToInt32()
	result = append(result, v)
}
fmt.Printf("result=%v", result) 
uint32 slice
// encode
data := []uint32{123, 456}
var node = y3.NewNodeSlicePacketEncoder(0x10)
if out, ok := utils.ToUInt64Slice(data); ok {
	for _, v := range out {
		var item = y3.NewPrimitivePacketEncoder(0x00)
		item.SetUInt32Value(uint32(v.(uint64)))
		node.AddPrimitivePacket(item)
	}
}
buf := node.Encode()
// decode
packet, _, _ := y3.DecodeNodePacket(buf)
result := make([]uint32, 0)
for _, p := range packet.PrimitivePackets {
	v, _ := p.ToUInt32()
	result = append(result, v)
}
fmt.Printf("result=%v", result) 
int64 slice
// encode
data := []int64{123, 456}
var node = y3.NewNodeSlicePacketEncoder(0x10)
if out, ok := utils.ToInt64Slice(data); ok {
	for _, v := range out {
		var item = y3.NewPrimitivePacketEncoder(0x00)
		item.SetInt64Value(v.(int64))
		node.AddPrimitivePacket(item)
	}
}
buf := node.Encode()
// decode
packet, _, _ := y3.DecodeNodePacket(buf)
result := make([]int64, 0)
for _, p := range packet.PrimitivePackets {
	v, _ := p.ToInt64()
	result = append(result, v)
}
fmt.Printf("result=%v", result) 
uint64 slice
data := []uint64{123, 456}
var node = y3.NewNodeSlicePacketEncoder(0x10)
if out, ok := utils.ToUInt64Slice(data); ok {
	for _, v := range out {
		var item = y3.NewPrimitivePacketEncoder(0x00)
		item.SetUInt64Value(v.(uint64))
		node.AddPrimitivePacket(item)
	}
}
buf := node.Encode()
// decode
packet, _, _ := y3.DecodeNodePacket(buf)
result := make([]uint64, 0)
for _, p := range packet.PrimitivePackets {
	v, _ := p.ToUInt64()
	result = append(result, v)
}
fmt.Printf("result=%v", result)  
float32 slice
// encode
data := []float32{1.23, 4.56}
var node = y3.NewNodeSlicePacketEncoder(0x10)
if out, ok := utils.ToUFloat64Slice(data); ok {
	for _, v := range out {
		var item = y3.NewPrimitivePacketEncoder(0x00)
		item.SetFloat32Value(float32(v.(float64)))
		node.AddPrimitivePacket(item)
	}
}
buf := node.Encode()
// decode
packet, _, _ := y3.DecodeNodePacket(buf)
result := make([]float32, 0)
for _, p := range packet.PrimitivePackets {
	v, _ := p.ToFloat32()
	result = append(result, v)
}
fmt.Printf("result=%v", result) 
float64 slice
// encode
data := []float64{1.23, 4.56}
var node = y3.NewNodeSlicePacketEncoder(0x10)
if out, ok := utils.ToUFloat64Slice(data); ok {
	for _, v := range out {
		var item = y3.NewPrimitivePacketEncoder(0x00)
		item.SetFloat64Value(v.(float64))
		node.AddPrimitivePacket(item)
	}
}
buf := node.Encode()
// decode
packet, _, _ := y3.DecodeNodePacket(buf)
result := make([]float64, 0)
for _, p := range packet.PrimitivePackets {
	v, _ := p.ToFloat64()
	result = append(result, v)
}
fmt.Printf("result=%v", result)  
bool slice
// encode
data := []bool{true, false}
var node = y3.NewNodeSlicePacketEncoder(0x10)
if out, ok := utils.ToBoolSlice(data); ok {
	for _, v := range out {
		var item = y3.NewPrimitivePacketEncoder(0x00)
		item.SetBoolValue(v.(bool))
		node.AddPrimitivePacket(item)
	}
}
buf := node.Encode()
// decode
packet, _, _ := y3.DecodeNodePacket(buf)
result := make([]bool, 0)
for _, p := range packet.PrimitivePackets {
	v, _ := p.ToBool()
	result = append(result, v)
}
fmt.Printf("result=%v", result)  
string slice
// encode
data := []string{"abc", "def"}
var node = y3.NewNodeSlicePacketEncoder(0x10)
if out, ok := utils.ToStringSlice(data); ok {
	for _, v := range out {
		var item = y3.NewPrimitivePacketEncoder(0x00)
		item.SetStringValue(fmt.Sprintf("%v", v))
		node.AddPrimitivePacket(item)
	}
}
buf := node.Encode()
// decode
packet, _, _ := y3.DecodeNodePacket(buf)
result := make([]string, 0)
for _, p := range packet.PrimitivePackets {
	v, _ := p.ToUTF8String()
	result = append(result, v)
}
fmt.Printf("result=%v", result) 
complex types
// encode
var node = y3.NewNodePacketEncoder(0x01)
node.AddPrimitivePacket(func() *y3.PrimitivePacketEncoder {
	var prim1 = y3.NewPrimitivePacketEncoder(0x10)
	prim1.SetFloat32Value(40.5)
	return prim1
}())
node.AddPrimitivePacket(func() *y3.PrimitivePacketEncoder {
	var prim1 = y3.NewPrimitivePacketEncoder(0x11)
	prim1.SetInt64Value(time.Now().Unix())
	return prim1
}())
buf := node.Encode()
// decode
res, _, _ := y3.DecodeNodePacket(buf)
for _, v := range res.PrimitivePackets {
	if v.SeqID() == 0x10 {
		fmt.Printf("0x10=%f\n", func() float32 {
			val, _ := v.ToFloat32()
			return val
		}())
	}
	if v.SeqID() == 0x11 {
		fmt.Printf("0x11=%d\n", func() int64 {
			val, _ := v.ToInt64()
			return val
		}())
	}
}  
complex slice types
// encode
var node = y3.NewNodeSlicePacketEncoder(0x01)
for i := 0; i < 2; i++ {
	item := y3.NewNodePacketEncoder(0x00)
	item.AddPrimitivePacket(func() *y3.PrimitivePacketEncoder {
		var prim1 = y3.NewPrimitivePacketEncoder(0x10)
		prim1.SetFloat32Value(40.5)
		return prim1
	}())
	item.AddPrimitivePacket(func() *y3.PrimitivePacketEncoder {
		var prim1 = y3.NewPrimitivePacketEncoder(0x11)
		prim1.SetInt64Value(time.Now().Unix())
		return prim1
	}())
	node.AddNodePacket(item)
}
buf := node.Encode()
// decode
res, _, _ := y3.DecodeNodePacket(buf)
for _, v := range res.NodePackets {
	if res.SeqID() != 0x01 {
		continue
	}
	for _, vv := range v.PrimitivePackets {
		if vv.SeqID() == 0x10 {
			fmt.Printf("0x10=%f\n", func() float32 {
				val, _ := vv.ToFloat32()
				return val
			}())
		}
		if vv.SeqID() == 0x11 {
			fmt.Printf("0x11=%d\n", func() int64 {
				val, _ := vv.ToInt64()
				return val
			}())
		}
	}
} 

Contributors

License

FOSSA Status