rtl

package module
v1.2.1 Latest Latest
Warning

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

Go to latest
Published: Feb 10, 2024 License: Apache-2.0 Imports: 16 Imported by: 12

README

go-rtl

这是一款使用简单,灵活方便,兼容性强的序列化工具。使用RTL(Recursive Typed and Length-prefixed)编码方式的golang对象的序列化及反序列化方法库。目前尚不支持其他语言。

由于go基础库中不存在通用序列化工具;且如protobuf的第三方序列化需要预定义文件及相应的生成工具,当序列化类型经常变化或很多时,工作会显得有些繁琐。为了能够简单使用而开发这个通用序列化工具包。

特性

  • 使用简单,可以将任意对象序列化成字节流,并反序列化为兼容的对象。
  • 序列化后,除原值外的附加信息很少。
  • struct类型升级可以兼容,即不同版本数据可以反序列化为不同版本类型的对象。
  • 支持类型的自定义序列化方式,可以与通用方法混用。

使用限制

  • 因为使用反射,序列化会比硬编码的序列化方式慢。
  • 因为无法确定代码中希望为哪种类型对象,无法将数据反序列化至interface{}中。但序列化是可以的,因为此时的interface{}类型是明确的。
  • 在struct类型升级兼容性中,不支持删除其中的自定义序列化方式的字段。

使用方法

1. 引用

go.mod

require github.com/stephenfire/go-rtl v1.0.4

go文件

import "github.com/stephenfire/go-rtl"
2. 序列化对象

由于使用reflect包,所以struct只有public的属性才可以被序列化和反序列化。

    type (
        embeded struct {
            A uint
            B uint
            C string
            D []byte
        }
        basic struct {
            A uint
            B uint
            C string
            E int
            F *big.Int
            G embeded
        }
    )

    obj := basic{
        A: 22,
        B: 33,
        C: "basic object",
        E: -983,
        F: big.NewInt(9999999),
        G: embeded{A: 44, B: 55, C: "embeded object", D: []byte("byte slice")},
    }
    buf := new(bytes.Buffer)
    if err := Encode(obj, buf); err != nil {
        t.Fatal(err)
    }
    bs := buf.Bytes()

    bs, err := Marshal(obj)
    if err != nil {
        t.Fatal(err)
    }
3. 反序列化对象,注意必须传入对象指针
    decodedObj := new(basic)
    if err := Decode(bytes.NewReader(bs), decodedObj); err != nil {
        t.Fatal(err)
    }

    decodedObj := new(basic)
    if err := Unmarshal(bs, decodedObj); err != nil {
        t.Fatal(err)
    }
4. 基础类型序列化

基本上所有类型均可

    var a, b int
    a = 142857
    if bs, err := Marshal(a); err == nil {
        if err = Unmarshal(bs, &b); err == nil {
            if a == b {
                t.Logf("%d == %d", a, b)
            } else {
                t.Fatalf("%d <> %d", a, b)
            }
        } else {
            t.Fatal(err)
        }
    } else {
        t.Fatal(err)
    }

    var x, y []int
    x = []int{1, 4, 2, 8, 5, 7}
    y = make([]int, 0)
    if bs, err := Marshal(x); err == nil {
        if err = Unmarshal(bs, &y); err == nil {
            if reflect.DeepEqual(x, y) {
                t.Logf("%v == %v", x, y)
            } else {
                t.Fatalf("%v <> %v", x, y)
            }
        } else {
            t.Fatal(err)
        }
    } else {
        t.Fatal(err)
    }
5. 类型兼容转化

结构对象序列化的原数据与目标数据兼容时即可正常反序列化,与属性位置相关

	type (
		source struct {
			A []byte
			B []byte
		}
		dest struct {
			C string
			D []int
		}
	)

	src := &source{A: []byte("a string"), B: []byte{0x1, 0x2, 0x3, 0x4}}
	if bs, err := Marshal(src); err != nil {
		t.Fatal(err)
	} else {
		dst := new(dest)
		if err := Unmarshal(bs, dst); err != nil {
			t.Fatal(err)
		}
		t.Logf("%+v -> %+v", src, dst)
	}

输出:

&{A:[97 32 115 116 114 105 110 103] B:[1 2 3 4]} -> &{C:a string D:[1 2 3 4]}
6. 结构类型的版本兼容性

通过使用标记 rtlorder 对结构属性进行排序。缺省为按定义顺序从0开始递增的值。

序列化时,按rtlorder的顺序写入buffer,遇到不连续的情况时,用ZeroValue占位。

反序列化时,按rtlorder的顺序读buffer,遇到不连续的情况时,跳过buffer中对应的位置;如果buffer数据不足,则反序列化对象中的后续属性均为缺省零值。

	type (
		source struct {
			A uint   // `rtlorder:"0"`
			B uint   // `rtlorder:"1"`
			C string // `rtlorder:"2"`
			D []byte // `rtlorder:"3"`
		}
		dest struct {
			E *big.Int `rtlorder:"4"`
			F int      `rtlorder:"5"`
			C string   `rtlorder:"2"`
			B uint     `rtlorder:"1"`
		}
	)

	src := &source{
		A: 1,
		B: 2,
		C: "Charlie",
		D: []byte("not in"),
	}
	if bs, err := Marshal(src); err != nil {
		t.Fatal(err)
	} else {
		dst := new(dest)
		if err := Unmarshal(bs, dst); err != nil {
			t.Fatal(err)
		}
		t.Logf("%+v -> %+v", src, dst)
	}

输出:

&{A:1 B:2 C:Charlie D:[110 111 116 32 105 110]} -> &{E:<nil> F:0 C:Charlie B:2}

Documentation

Index

Constants

View Source
const (
	MaxSliceSize = 100 * 1024 * 1024 // max size of creating slice: 100MB
	MaxNested    = 100               // max nested times when encoding. pointer, slice, array, map, struct
)

Variables

View Source
var (
	NilOrFalse   = headerTypeMap[THZeroValue].C
	NotNilOrTrue = headerTypeMap[THTrue].C
	Version0     = headerTypeMap[THVersion].WithNumber(0x0)
	Version1     = headerTypeMap[THVersion].WithNumber(0x1)
	Version2     = headerTypeMap[THVersion].WithNumber(0x2)
	Version3     = headerTypeMap[THVersion].WithNumber(0x3)
	Version4     = headerTypeMap[THVersion].WithNumber(0x4)
	Version5     = headerTypeMap[THVersion].WithNumber(0x5)
	Version6     = headerTypeMap[THVersion].WithNumber(0x6)
	Version7     = headerTypeMap[THVersion].WithNumber(0x7)
	Version8     = headerTypeMap[THVersion].WithNumber(0x8)
	Version9     = headerTypeMap[THVersion].WithNumber(0x9)
	Version10    = headerTypeMap[THVersion].WithNumber(0xa)
	Version11    = headerTypeMap[THVersion].WithNumber(0xb)
	Version12    = headerTypeMap[THVersion].WithNumber(0xc)
	Version13    = headerTypeMap[THVersion].WithNumber(0xd)
	Version14    = headerTypeMap[THVersion].WithNumber(0xe)
	Version15    = headerTypeMap[THVersion].WithNumber(0xf)
)
View Source
var (

	// header maker of encoding
	HeadMaker headMaker

	// codec for numerics
	Numeric numeric

	// serialize/deserialize self
	TypeOfEncoderPtr = reflect.TypeOf((*Encoder)(nil))
	TypeOfEncoder    = TypeOfEncoderPtr.Elem()
	TypeOfDecoderPtr = reflect.TypeOf((*Decoder)(nil))
	TypeOfDecoder    = TypeOfDecoderPtr.Elem()

	// errors
	ErrUnsupported        = errors.New("unsupported")
	ErrNestingOverflow    = fmt.Errorf("nesting overflow: %d times", MaxNested)
	ErrInsufficientLength = errors.New("insufficient length of the slice")
	ErrDecode             = errors.New("decode error")
	ErrLength             = errors.New("length error")
	ErrTooLarge           = errors.New("too large to create")
	ErrDecodeIntoNil      = errors.New("rtl: decode pointer MUST NOT be nil")
	ErrDecodeNoPtr        = errors.New("rtl: value being decode MUST be a pointer")

	ErrEmptyStack   = errors.New("rtl: stack is empty")
	ErrInvalidValue = errors.New("invalid reflect.Value")
)

Functions

func BinaryToInt

func BinaryToInt(bs []byte) int64

func BinaryToUint

func BinaryToUint(bs []byte) uint64

func Convertible added in v1.2.1

func Convertible(src, dest reflect.Type) bool

func ConvertiblePtr added in v1.2.1

func ConvertiblePtr(src, dest reflect.Type) bool

func ConvertibleTo added in v1.2.1

func ConvertibleTo(src, dest reflect.Type) bool

func Decode

func Decode(r io.Reader, v interface{}) error

Decode reads bytes from r unmarshal to v, if you want to use same Reader to Decode multi values, you should use encoding.ValueReader as io.Reader.

func DecodeBigInt

func DecodeBigInt(r io.Reader, v interface{}) error

func DecodeV1 added in v1.1.1

func DecodeV1(r io.Reader, v interface{}) error

func DecodeV2 added in v1.1.1

func DecodeV2(r io.Reader, v interface{}) error

func Encode

func Encode(v interface{}, w io.Writer) error

func EncodeBigInt

func EncodeBigInt(v interface{}, w io.Writer) error

func EndOfFile

func EndOfFile(err error) bool

func Marshal

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

func ReadBytesFromReader

func ReadBytesFromReader(r io.Reader, length int, buf []byte) ([]byte, error)

func ReadMultiLengthBytesFromReader

func ReadMultiLengthBytesFromReader(vr ValueReader, length int, buf []byte) ([]byte, error)

func ReadMultiLengthFromReader

func ReadMultiLengthFromReader(vr ValueReader, length int) (uint64, error)

func ToBinaryBuffer

func ToBinaryBuffer(v interface{}, w io.Writer) error

func ToBinaryBytes

func ToBinaryBytes(v interface{}) (ret []byte)

ToBinaryBytes

func Unmarshal

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

Types

type Decoder

type Decoder interface {
	Deserialization(r io.Reader) (shouldBeNil bool, err error)
}

type DefaultEventHandler added in v1.1.1

type DefaultEventHandler struct{}

func (DefaultEventHandler) Array added in v1.1.1

func (DefaultEventHandler) Byte added in v1.1.1

func (DefaultEventHandler) Bytes added in v1.1.1

func (DefaultEventHandler) Empty added in v1.1.1

func (DefaultEventHandler) Number added in v1.1.1

func (h DefaultEventHandler) Number(_ *HandleContext, _ reflect.Value, _ bool, _ []byte) error

func (DefaultEventHandler) True added in v1.1.1

func (DefaultEventHandler) Version added in v1.1.1

func (h DefaultEventHandler) Version(_ *HandleContext, _ reflect.Value, _ ...byte) error

func (DefaultEventHandler) Zero added in v1.1.1

type Encoder

type Encoder interface {
	Serialization(w io.Writer) error
}

Encoder is the interface which encoding package while invoke the Serialization() when encoding the object. ATTENTION: the receiver of Encoder.Serialization() and Decoder.Deserialization() MUST BE SAME. otherwise, they will not be use in same struct.

type EventDecoder added in v1.1.0

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

func (*EventDecoder) Decode added in v1.1.0

func (e *EventDecoder) Decode(r io.Reader, obj interface{}) error

type EventHandler added in v1.1.1

type EventHandler interface {
	Byte(ctx *HandleContext, value reflect.Value, input byte) error
	Zero(ctx *HandleContext, value reflect.Value) error
	True(ctx *HandleContext, value reflect.Value) error
	Empty(ctx *HandleContext, value reflect.Value) error
	Array(ctx *HandleContext, value reflect.Value, length int) error
	Number(ctx *HandleContext, value reflect.Value, isPositive bool, inputs []byte) error
	Bytes(ctx *HandleContext, value reflect.Value, inputs []byte) error
	Version(ctx *HandleContext, value reflect.Value, inputs ...byte) error
}

type HandleContext added in v1.1.0

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

func NewHandleContext added in v1.1.1

func NewHandleContext(r io.Reader) *HandleContext

func (*HandleContext) NestedStack added in v1.1.1

func (ctx *HandleContext) NestedStack(handler NestedHandler) error

func (*HandleContext) NewNested added in v1.1.1

func (ctx *HandleContext) NewNested(typ reflect.Type) interface{}

func (*HandleContext) PopState added in v1.1.1

func (ctx *HandleContext) PopState() error

func (*HandleContext) PushState added in v1.1.1

func (ctx *HandleContext) PushState(val reflect.Value, th TypeHeader, length int, buf []byte, handler NestedHandler) error

func (*HandleContext) ReplaceStack added in v1.1.1

func (ctx *HandleContext) ReplaceStack(val reflect.Value) error

func (*HandleContext) SkipReader added in v1.1.1

func (ctx *HandleContext) SkipReader(length int) error

func (*HandleContext) StackInfo added in v1.1.0

func (ctx *HandleContext) StackInfo() string

func (*HandleContext) String added in v1.1.0

func (ctx *HandleContext) String() string

type Lenner added in v1.0.2

type Lenner interface {
	Len() int
}

type NestedHandler added in v1.1.0

type NestedHandler interface {
	String() string
	Element(ctx *HandleContext) error
	Index() int
}

type StructCodec

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

func NewStructCodec

func NewStructCodec(typ reflect.Type) (*StructCodec, error)

func (*StructCodec) Decode

func (c *StructCodec) Decode(r io.Reader) (interface{}, error)

func (*StructCodec) Encode

func (c *StructCodec) Encode(o interface{}, w io.Writer) error

type THValue

type THValue struct {
	N string      // name of the type header
	C byte        // code
	M byte        // mask
	W byte        // wildcard mask
	T THValueType // type of the header
	B bool        // whether the header is followed by value bytes
	X bool        // whether the type is a nested type, which means there's should be another header follow the current header
}

type header value

func (THValue) Match

func (thvalue THValue) Match(b byte) bool

func (THValue) WithNumber

func (thvalue THValue) WithNumber(b byte) byte

type THValueType

type THValueType byte
const (
	THVTByte         THValueType = iota // one byte value
	THVTSingleHeader                    // single byte header
	THVTMultiHeader                     // multi bytes header
	THVTInvalid
)

type TypeHeader

type TypeHeader byte
const (
	THSingleByte    TypeHeader = iota // single byte
	THZeroValue                       // zero value (empty string / false of bool)
	THTrue                            // true of bool
	THEmpty                           // empty value
	THArraySingle                     // array with no more than 16 elements
	THArrayMulti                      // array with more than 16 elements
	THPosNumSingle                    // positive number with bytes less and equal to 8
	THNegNumSingle                    // negative number with bytes less and equal to 8
	THPosBigInt                       // positive big.Int
	THNegBigInt                       // negative big.Int
	THStringSingle                    // string with length less and equal to 32
	THStringMulti                     // string with length more than 32
	THVersion                         // 0 <= (version number) <= 15
	THVersionSingle                   // 15 < (version number) < 2^64
	THInvalid
)

func ParseRTLHeader

func ParseRTLHeader(b byte) (TypeHeader, int, error)

func (TypeHeader) FollowedByBytes added in v1.1.0

func (th TypeHeader) FollowedByBytes() bool

func (TypeHeader) FollowedByHeader added in v1.1.0

func (th TypeHeader) FollowedByHeader() bool

func (TypeHeader) IsValid added in v1.1.0

func (th TypeHeader) IsValid() bool

func (TypeHeader) Name

func (th TypeHeader) Name() string

func (TypeHeader) Nested added in v1.1.0

func (th TypeHeader) Nested() bool

func (TypeHeader) String

func (th TypeHeader) String() string

func (TypeHeader) ValueType added in v1.1.0

func (th TypeHeader) ValueType() (THValueType, bool)

type ValueReader

type ValueReader interface {
	HasMore() bool
	ReadHeader() (TypeHeader, int, error)
	ReadFullHeader() (TypeHeader, int, error)
	io.ByteReader
	io.Reader
	ReadBytes(length int, buf []byte) ([]byte, error)
	ReadMultiLength(length int) (uint64, error)
	ReadMultiLengthBytes(length int, buf []byte) ([]byte, error)
	Skip() (int, error)
}

func NewValueReader

func NewValueReader(r io.Reader, _ ...int) ValueReader

Jump to

Keyboard shortcuts

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