init
This commit is contained in:
		
						commit
						3680ef7a22
					
				|  | @ -0,0 +1,72 @@ | ||||||
|  | package mq_coder | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"bytes" | ||||||
|  | 	"io" | ||||||
|  | 	"io/ioutil" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | type chunkVReader struct { | ||||||
|  | 	src        io.Reader     // the reader parts of V
 | ||||||
|  | 	buf        *bytes.Buffer // the bytes part of V
 | ||||||
|  | 	totalSize  int           // size of whole buffer of this packet
 | ||||||
|  | 	off        int           // last read op
 | ||||||
|  | 	ChunkVSize int           // the size of chunked V
 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Read implement io.Reader interface
 | ||||||
|  | func (r *chunkVReader) Read(p []byte) (n int, err error) { | ||||||
|  | 	if r.src == nil { | ||||||
|  | 		return 0, nil | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if r.off >= r.totalSize { | ||||||
|  | 		return 0, io.EOF | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if r.off < r.totalSize-r.ChunkVSize { | ||||||
|  | 		n, err := r.buf.Read(p) | ||||||
|  | 		r.off += n | ||||||
|  | 		if err != nil { | ||||||
|  | 			if err == io.EOF { | ||||||
|  | 				return n, nil | ||||||
|  | 			} else { | ||||||
|  | 				return 0, err | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		return n, nil | ||||||
|  | 	} | ||||||
|  | 	n, err = r.src.Read(p) | ||||||
|  | 	r.off += n | ||||||
|  | 	if err != nil { | ||||||
|  | 		return n, err | ||||||
|  | 	} | ||||||
|  | 	return n, nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // WriteTo implement io.WriteTo interface
 | ||||||
|  | func (r *chunkVReader) WriteTo(w io.Writer) (n int64, err error) { | ||||||
|  | 	if r.src == nil { | ||||||
|  | 		return 0, nil | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// first, write existed buffer
 | ||||||
|  | 	m, err := w.Write(r.buf.Bytes()) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return 0, err | ||||||
|  | 	} | ||||||
|  | 	n += int64(m) | ||||||
|  | 
 | ||||||
|  | 	// last, write from reader
 | ||||||
|  | 	buf, err := ioutil.ReadAll(r.src) | ||||||
|  | 	if err != nil && err != io.EOF { | ||||||
|  | 		return 0, errWriteFromReader | ||||||
|  | 	} | ||||||
|  | 	m, err = w.Write(buf) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return 0, err | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	n += int64(m) | ||||||
|  | 	return n, nil | ||||||
|  | } | ||||||
|  | @ -0,0 +1,54 @@ | ||||||
|  | package mq_coder | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"errors" | ||||||
|  | 	"io" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | var ( | ||||||
|  | 	errBuildIncomplete = errors.New("coder.Encoder: invalid structure of packet") | ||||||
|  | 	errInvalidAdding   = errors.New("coder.Encoder: can not add this Packet after StreamPacket has been add") | ||||||
|  | 	errNonStreamPacket = errors.New("coder.Packet: this packet is not in node mode") | ||||||
|  | 	errWriteFromReader = errors.New("coder.streamV: write from reader error") | ||||||
|  | 	errNotNodeMode     = errors.New("coder.Encoder: packet should be in node mode can be add other packets as child") | ||||||
|  | 	errNilReader       = errors.New("coder.Decoder: nil source reader") | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | // Packet 编解码器包
 | ||||||
|  | type Packet interface { | ||||||
|  | 	// SeqId 返回此数据包的序列Id.
 | ||||||
|  | 	SeqId() int | ||||||
|  | 	// Size 返回整个数据包的大小
 | ||||||
|  | 	Size() int | ||||||
|  | 	// VSize 返回V的大小.
 | ||||||
|  | 	VSize() int | ||||||
|  | 	// Bytes 此数据包的全部字节.
 | ||||||
|  | 	Bytes() []byte | ||||||
|  | 	// Reader 返回 io.Reader 字节.
 | ||||||
|  | 	Reader() io.Reader | ||||||
|  | 	// VReader 返回 io.Reader 的 流字节.
 | ||||||
|  | 	VReader() io.Reader | ||||||
|  | 	// IsStreamMode 是否流模式
 | ||||||
|  | 	IsStreamMode() bool | ||||||
|  | 	// IsNodeMode 是否节点模式
 | ||||||
|  | 	IsNodeMode() bool | ||||||
|  | 
 | ||||||
|  | 	// BytesV 返回流字节
 | ||||||
|  | 	BytesV() []byte | ||||||
|  | 	// UTF8StringV 返回流的utf8字符串值
 | ||||||
|  | 	UTF8StringV() string | ||||||
|  | 	// Int32V 返回流的int32值
 | ||||||
|  | 	Int32V() (val int32, err error) | ||||||
|  | 	// UInt32V 返回流的uint32值
 | ||||||
|  | 	UInt32V() (val uint32, err error) | ||||||
|  | 	// Int64V 返回流的int64值
 | ||||||
|  | 	Int64V() (val int64, err error) | ||||||
|  | 	// UInt64V 返回流的uint64值
 | ||||||
|  | 	UInt64V() (val uint64, err error) | ||||||
|  | 	// Float32V 返回流的float32值
 | ||||||
|  | 	Float32V() (val float32, err error) | ||||||
|  | 	// Float64V 返回流的float64值
 | ||||||
|  | 	Float64V() (val float64, err error) | ||||||
|  | 	// BoolV 返回流的bool值
 | ||||||
|  | 	BoolV() (val bool, err error) | ||||||
|  | } | ||||||
|  | @ -0,0 +1,93 @@ | ||||||
|  | package mq_coder | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"bytes" | ||||||
|  | 	"io" | ||||||
|  | 
 | ||||||
|  | 	"git.hpds.cc/Component/mq_coder/spec" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | // Decoder is the tool for decoding packet from stream
 | ||||||
|  | type Decoder struct { | ||||||
|  | 	tag spec.T | ||||||
|  | 	len *spec.L | ||||||
|  | 	rd  io.Reader | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // NewDecoder returns a Decoder from an io.Reader
 | ||||||
|  | func NewDecoder(reader io.Reader) *Decoder { | ||||||
|  | 	return &Decoder{ | ||||||
|  | 		rd: reader, | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // SeqID return the SequenceID of the decoding packet
 | ||||||
|  | func (d *Decoder) SeqID() int { | ||||||
|  | 	return d.tag.Sid() | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // UnderlyingReader returns the reader this decoder using
 | ||||||
|  | func (d *Decoder) UnderlyingReader() io.Reader { | ||||||
|  | 	return d.rd | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // ReadHeader will block until io.EOF or receive T and L of a packet.
 | ||||||
|  | func (d *Decoder) ReadHeader() error { | ||||||
|  | 	// only read T and L
 | ||||||
|  | 	return d.readTL() | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // GetChunkedPacket will block until io.EOF or receive V of a packet in chunked mode.
 | ||||||
|  | func (d *Decoder) GetChunkedPacket() Packet { | ||||||
|  | 	return &StreamPacket{ | ||||||
|  | 		t:         d.tag, | ||||||
|  | 		l:         *d.len, | ||||||
|  | 		vr:        d.rd, | ||||||
|  | 		chunkMode: true, | ||||||
|  | 		chunkSize: d.len.VSize(), | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // GetFullFilledPacket read full Packet from given io.Reader
 | ||||||
|  | func (d *Decoder) GetFullFilledPacket() (packet Packet, err error) { | ||||||
|  | 	// read V
 | ||||||
|  | 	buf := new(bytes.Buffer) | ||||||
|  | 	total := 0 | ||||||
|  | 	for { | ||||||
|  | 		valBuf := make([]byte, d.len.VSize()) | ||||||
|  | 		n, err := d.rd.Read(valBuf) | ||||||
|  | 		if n > 0 { | ||||||
|  | 			total += n | ||||||
|  | 			buf.Write(valBuf[:n]) | ||||||
|  | 		} | ||||||
|  | 		if total >= d.len.VSize() || err != nil { | ||||||
|  | 			break | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	packet = &StreamPacket{ | ||||||
|  | 		t:         d.tag, | ||||||
|  | 		l:         *d.len, | ||||||
|  | 		vbuf:      buf.Bytes(), | ||||||
|  | 		chunkMode: false, | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return packet, nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (d *Decoder) readTL() (err error) { | ||||||
|  | 	if d.rd == nil { | ||||||
|  | 		return errNilReader | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// read T
 | ||||||
|  | 	d.tag, err = spec.ReadT(d.rd) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// read L
 | ||||||
|  | 	d.len, err = spec.ReadL(d.rd) | ||||||
|  | 
 | ||||||
|  | 	return err | ||||||
|  | } | ||||||
|  | @ -0,0 +1,158 @@ | ||||||
|  | package mq_coder | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"bytes" | ||||||
|  | 	"io" | ||||||
|  | 
 | ||||||
|  | 	"git.hpds.cc/Component/mq_coder/spec" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | // Encoder is the tool for creating a packet easily
 | ||||||
|  | type Encoder struct { | ||||||
|  | 	tag           spec.T | ||||||
|  | 	len           *spec.L | ||||||
|  | 	valReader     io.Reader | ||||||
|  | 	valReaderSize int | ||||||
|  | 	nodes         map[int]Packet | ||||||
|  | 	state         int | ||||||
|  | 	size          int32 // size of value
 | ||||||
|  | 	isStreamMode  bool | ||||||
|  | 	valBuf        *bytes.Buffer | ||||||
|  | 	done          bool | ||||||
|  | 	seqID         int | ||||||
|  | 	isNodeMode    bool | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // SetSeqId set sequenceId of a  packet, if this packet contains other
 | ||||||
|  | // packets, isNode should set to true
 | ||||||
|  | func (b *Encoder) SetSeqId(seqId int, isNode bool) { | ||||||
|  | 	// init
 | ||||||
|  | 	b.valBuf = new(bytes.Buffer) | ||||||
|  | 	b.nodes = make(map[int]Packet) | ||||||
|  | 	// set seqID
 | ||||||
|  | 	b.seqID = seqId | ||||||
|  | 	b.isNodeMode = isNode | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // SetBytesV set bytes type as V
 | ||||||
|  | func (b *Encoder) SetBytesV(buf []byte) { | ||||||
|  | 	b.size += int32(len(buf)) | ||||||
|  | 	b.valBuf.Write(buf) | ||||||
|  | 	b.isStreamMode = false | ||||||
|  | 	b.state |= 0x04 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // SetReaderV set io.Reader type as V
 | ||||||
|  | func (b *Encoder) SetReaderV(r io.Reader, size int) { | ||||||
|  | 	b.isStreamMode = true | ||||||
|  | 	b.valReader = r | ||||||
|  | 	b.state |= 0x04 | ||||||
|  | 	b.size += int32(size) | ||||||
|  | 	b.valReaderSize = size | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // AddPacket add a Packet child to this packet, this packet must be NodeMode
 | ||||||
|  | func (b *Encoder) AddPacket(child Packet) error { | ||||||
|  | 	// only packet is in node mode can add other packets
 | ||||||
|  | 	if !b.isNodeMode { | ||||||
|  | 		return errNotNodeMode | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if b.done { | ||||||
|  | 		return errInvalidAdding | ||||||
|  | 	} | ||||||
|  | 	b.nodes[child.SeqId()] = child | ||||||
|  | 	buf := child.Bytes() | ||||||
|  | 	b.SetBytesV(buf) | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // AddStreamPacket will put a StreamPacket in chunked mode to current packet.
 | ||||||
|  | func (b *Encoder) AddStreamPacket(child Packet) (err error) { | ||||||
|  | 	// if this packet is in stream mode, can not add any packets
 | ||||||
|  | 	if b.done { | ||||||
|  | 		return errInvalidAdding | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// only accept packet in stream mode
 | ||||||
|  | 	if !child.IsStreamMode() { | ||||||
|  | 		return errNonStreamPacket | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// set the valReader of this packet to the child's
 | ||||||
|  | 	b.valReader = child.VReader() | ||||||
|  | 
 | ||||||
|  | 	// valReaderSize will be the same as child's
 | ||||||
|  | 	b.valReaderSize = child.VSize() | ||||||
|  | 	// add this child packet
 | ||||||
|  | 	b.nodes[child.SeqId()] = child | ||||||
|  | 	// add the size of child's V to L of this packet
 | ||||||
|  | 	b.size += int32(child.Size()) | ||||||
|  | 	// put the bytes of child to valBuf
 | ||||||
|  | 	buf := child.Bytes() | ||||||
|  | 	b.valBuf.Write(buf) | ||||||
|  | 	// update state
 | ||||||
|  | 	b.state |= 0x04 | ||||||
|  | 	b.isStreamMode = true | ||||||
|  | 	b.done = true | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Packet return a Packet instance.
 | ||||||
|  | func (b *Encoder) Packet() (Packet, error) { | ||||||
|  | 	err := b.generateT() | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	err = b.generateL() | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if b.state != 0x07 { | ||||||
|  | 		return nil, errBuildIncomplete | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if b.isStreamMode { | ||||||
|  | 		return &StreamPacket{ | ||||||
|  | 			t:         b.tag, | ||||||
|  | 			l:         *b.len, | ||||||
|  | 			vr:        b.valReader, | ||||||
|  | 			vbuf:      b.valBuf.Bytes(), | ||||||
|  | 			chunkMode: true, | ||||||
|  | 			chunkSize: b.valReaderSize, | ||||||
|  | 		}, err | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// not streaming mode
 | ||||||
|  | 	return &StreamPacket{ | ||||||
|  | 		t:         b.tag, | ||||||
|  | 		l:         *b.len, | ||||||
|  | 		vbuf:      b.valBuf.Bytes(), | ||||||
|  | 		chunkMode: false, | ||||||
|  | 	}, err | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // will generate T of a TLV.
 | ||||||
|  | func (b *Encoder) generateT() error { | ||||||
|  | 	t, err := spec.NewT(b.seqID) | ||||||
|  | 	t.SetNodeMode(b.isNodeMode) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 	b.tag = t | ||||||
|  | 	b.state |= 0x01 | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // will generate L of a TLV.
 | ||||||
|  | func (b *Encoder) generateL() error { | ||||||
|  | 	l, err := spec.NewL(int(b.size)) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 	b.len = &l | ||||||
|  | 	b.state |= 0x02 | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  | @ -0,0 +1,98 @@ | ||||||
|  | package mq_coder | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"git.hpds.cc/Component/mq_coder/encoding" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | // SetUTF8StringV set utf-8 string type value as V
 | ||||||
|  | func (b *Encoder) SetUTF8StringV(v string) { | ||||||
|  | 	buf := []byte(v) | ||||||
|  | 	b.SetBytesV(buf) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // SetInt32V set an int32 type value as V
 | ||||||
|  | func (b *Encoder) SetInt32V(v int32) error { | ||||||
|  | 	size := encoding.SizeOfNVarInt32(v) | ||||||
|  | 	codec := encoding.VarCodec{Size: size} | ||||||
|  | 	buf := make([]byte, size) | ||||||
|  | 	err := codec.EncodeNVarInt32(buf, v) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 	b.SetBytesV(buf) | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // SetUInt32V set an uint32 type value as V
 | ||||||
|  | func (b *Encoder) SetUInt32V(v uint32) error { | ||||||
|  | 	size := encoding.SizeOfNVarUInt32(v) | ||||||
|  | 	codec := encoding.VarCodec{Size: size} | ||||||
|  | 	buf := make([]byte, size) | ||||||
|  | 	err := codec.EncodeNVarUInt32(buf, v) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 	b.SetBytesV(buf) | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // SetInt64V set an int64 type value as V
 | ||||||
|  | func (b *Encoder) SetInt64V(v int64) error { | ||||||
|  | 	size := encoding.SizeOfNVarInt64(v) | ||||||
|  | 	codec := encoding.VarCodec{Size: size} | ||||||
|  | 	buf := make([]byte, size) | ||||||
|  | 	err := codec.EncodeNVarInt64(buf, v) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 	b.SetBytesV(buf) | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // SetUInt64V set an uint64 type value as V
 | ||||||
|  | func (b *Encoder) SetUInt64V(v uint64) error { | ||||||
|  | 	size := encoding.SizeOfNVarUInt64(v) | ||||||
|  | 	codec := encoding.VarCodec{Size: size} | ||||||
|  | 	buf := make([]byte, size) | ||||||
|  | 	err := codec.EncodeNVarUInt64(buf, v) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 	b.SetBytesV(buf) | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // SetFloat32V set a float32 type value as V
 | ||||||
|  | func (b *Encoder) SetFloat32V(v float32) error { | ||||||
|  | 	size := encoding.SizeOfVarFloat32(v) | ||||||
|  | 	codec := encoding.VarCodec{Size: size} | ||||||
|  | 	buf := make([]byte, size) | ||||||
|  | 	err := codec.EncodeVarFloat32(buf, v) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 	b.SetBytesV(buf) | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // SetFloat64V set a float64 type value as V
 | ||||||
|  | func (b *Encoder) SetFloat64V(v float64) error { | ||||||
|  | 	size := encoding.SizeOfVarFloat64(v) | ||||||
|  | 	codec := encoding.VarCodec{Size: size} | ||||||
|  | 	buf := make([]byte, size) | ||||||
|  | 	err := codec.EncodeVarFloat64(buf, v) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 	b.SetBytesV(buf) | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // SetBoolV set bool type value as V
 | ||||||
|  | func (b *Encoder) SetBoolV(v bool) { | ||||||
|  | 	var size = encoding.SizeOfPVarUInt32(uint32(1)) | ||||||
|  | 	codec := encoding.VarCodec{Size: size} | ||||||
|  | 	buf := make([]byte, size) | ||||||
|  | 	_ = codec.EncodePVarBool(buf, v) | ||||||
|  | 	b.SetBytesV(buf) | ||||||
|  | } | ||||||
|  | @ -0,0 +1,42 @@ | ||||||
|  | @startuml | ||||||
|  | namespace encoding { | ||||||
|  |     class VarCodec << (S,Aquamarine) >> { | ||||||
|  |         + Ptr int | ||||||
|  |         + Size int | ||||||
|  | 
 | ||||||
|  |         - encodeNVarInt(buffer []byte, value int64) error | ||||||
|  |         - decodeNVarInt(buffer []byte, value *int64) error | ||||||
|  |         - encodePVarInt(buffer []byte, value int64) error | ||||||
|  |         - decodePVarInt(buffer []byte, value *int64) error | ||||||
|  |         - encodeVarFloat(buffer []byte, bits uint64, width int) error | ||||||
|  |         - decodeVarFloat(buffer []byte, bits *uint64, width int) error | ||||||
|  |         - sizeOfGap(width int) (int, int) | ||||||
|  | 
 | ||||||
|  |         + EncodeNVarInt32(buffer []byte, value int32) error | ||||||
|  |         + DecodeNVarInt32(buffer []byte, value *int32) error | ||||||
|  |         + EncodeNVarUInt32(buffer []byte, value uint32) error | ||||||
|  |         + DecodeNVarUInt32(buffer []byte, value *uint32) error | ||||||
|  |         + EncodeNVarInt64(buffer []byte, value int64) error | ||||||
|  |         + DecodeNVarInt64(buffer []byte, value *int64) error | ||||||
|  |         + EncodeNVarUInt64(buffer []byte, value uint64) error | ||||||
|  |         + DecodeNVarUInt64(buffer []byte, value *uint64) error | ||||||
|  |         + EncodePVarBool(buffer []byte, value bool) error | ||||||
|  |         + DecodePVarBool(buffer []byte, value *bool) error | ||||||
|  |         + EncodePVarInt32(buffer []byte, value int32) error | ||||||
|  |         + DecodePVarInt32(buffer []byte, value *int32) error | ||||||
|  |         + EncodePVarUInt32(buffer []byte, value uint32) error | ||||||
|  |         + DecodePVarUInt32(buffer []byte, value *uint32) error | ||||||
|  |         + EncodePVarInt64(buffer []byte, value int64) error | ||||||
|  |         + DecodePVarInt64(buffer []byte, value *int64) error | ||||||
|  |         + EncodePVarUInt64(buffer []byte, value uint64) error | ||||||
|  |         + DecodePVarUInt64(buffer []byte, value *uint64) error | ||||||
|  |         + EncodeVarFloat32(buffer []byte, value float32) error | ||||||
|  |         + DecodeVarFloat32(buffer []byte, value *float32) error | ||||||
|  |         + EncodeVarFloat64(buffer []byte, value float64) error | ||||||
|  |         + DecodeVarFloat64(buffer []byte, value *float64) error | ||||||
|  | 
 | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | @enduml | ||||||
|  | @ -0,0 +1,132 @@ | ||||||
|  | package encoding | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"errors" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | // SizeOfNVarInt32 return the buffer size after encoding value as NVarInt32
 | ||||||
|  | func SizeOfNVarInt32(value int32) int { | ||||||
|  | 	return sizeOfNVarInt(int64(value), 32) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // EncodeNVarInt32 encode value as NVarInt32 to buffer
 | ||||||
|  | func (codec *VarCodec) EncodeNVarInt32(buffer []byte, value int32) error { | ||||||
|  | 	return codec.encodeNVarInt(buffer, int64(value)) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // DecodeNVarInt32 decode to value as NVarInt32 from buffer
 | ||||||
|  | func (codec *VarCodec) DecodeNVarInt32(buffer []byte, value *int32) error { | ||||||
|  | 	var val = int64(*value) | ||||||
|  | 	var err = codec.decodeNVarInt(buffer, &val) | ||||||
|  | 	*value = int32(val) | ||||||
|  | 	return err | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // SizeOfNVarUInt32 return the buffer size after encoding value as NVarUInt32
 | ||||||
|  | func SizeOfNVarUInt32(value uint32) int { | ||||||
|  | 	return sizeOfNVarInt(int64(int32(value)), 32) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // EncodeNVarUInt32 encode value as NVarUInt32 to buffer
 | ||||||
|  | func (codec *VarCodec) EncodeNVarUInt32(buffer []byte, value uint32) error { | ||||||
|  | 	return codec.encodeNVarInt(buffer, int64(int32(value))) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // DecodeNVarUInt32 decode to value as NVarUInt32 from buffer
 | ||||||
|  | func (codec *VarCodec) DecodeNVarUInt32(buffer []byte, value *uint32) error { | ||||||
|  | 	var val = int64(int32(*value)) | ||||||
|  | 	var err = codec.decodeNVarInt(buffer, &val) | ||||||
|  | 	*value = uint32(val) | ||||||
|  | 	return err | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // SizeOfNVarInt64 return the buffer size after encoding value as NVarInt64
 | ||||||
|  | func SizeOfNVarInt64(value int64) int { | ||||||
|  | 	return sizeOfNVarInt(value, 64) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // EncodeNVarInt64 encode value as NVarInt64 to buffer
 | ||||||
|  | func (codec *VarCodec) EncodeNVarInt64(buffer []byte, value int64) error { | ||||||
|  | 	return codec.encodeNVarInt(buffer, value) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // DecodeNVarInt64 decode to value as NVarInt64 from buffer
 | ||||||
|  | func (codec *VarCodec) DecodeNVarInt64(buffer []byte, value *int64) error { | ||||||
|  | 	return codec.decodeNVarInt(buffer, value) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // SizeOfNVarUInt64 return the buffer size after encoding value as NVarUInt64
 | ||||||
|  | func SizeOfNVarUInt64(value uint64) int { | ||||||
|  | 	return sizeOfNVarInt(int64(value), 64) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // EncodeNVarUInt64 encode value as NVarUInt64 to buffer
 | ||||||
|  | func (codec *VarCodec) EncodeNVarUInt64(buffer []byte, value uint64) error { | ||||||
|  | 	return codec.encodeNVarInt(buffer, int64(value)) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // DecodeNVarUInt64 decode to value as NVarUInt64 from buffer
 | ||||||
|  | func (codec *VarCodec) DecodeNVarUInt64(buffer []byte, value *uint64) error { | ||||||
|  | 	var val = int64(*value) | ||||||
|  | 	var err = codec.decodeNVarInt(buffer, &val) | ||||||
|  | 	*value = uint64(val) | ||||||
|  | 	return err | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // SizeOfNVarInt return the buffer size after encoding value as NVarInt
 | ||||||
|  | func sizeOfNVarInt(value int64, width int) int { | ||||||
|  | 	const unit = 8 // bit width of encoding unit
 | ||||||
|  | 
 | ||||||
|  | 	var lead = value >> (width - 1) | ||||||
|  | 	for size := width / unit - 1; size > 0; size-- { | ||||||
|  | 		var lookAhead = value >> (size*unit - 1) | ||||||
|  | 		if lookAhead != lead { | ||||||
|  | 			return size + 1 | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return 1 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (codec *VarCodec) encodeNVarInt(buffer []byte, value int64) error { | ||||||
|  | 	if codec == nil || codec.Size == 0 { | ||||||
|  | 		return errors.New("nothing to encode") | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	const unit = 8 // bit width of encoding unit
 | ||||||
|  | 	for codec.Size > 0 { | ||||||
|  | 		if codec.Ptr >= len(buffer) { | ||||||
|  | 			return ErrBufferInsufficient | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		codec.Size-- | ||||||
|  | 		buffer[codec.Ptr] = byte(value >> (codec.Size * unit)) | ||||||
|  | 		codec.Ptr++ | ||||||
|  | 	} | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (codec *VarCodec) decodeNVarInt(buffer []byte, value *int64) error { | ||||||
|  | 	if codec == nil || codec.Size == 0 { | ||||||
|  | 		return errors.New("nothing to decode") | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	const unit = 8      // bit width of encoding unit
 | ||||||
|  | 	if codec.Size > 0 { // initialize sign bit
 | ||||||
|  | 		if codec.Ptr >= len(buffer) { | ||||||
|  | 			return ErrBufferInsufficient | ||||||
|  | 		} | ||||||
|  | 		*value = int64(int8(buffer[codec.Ptr]) >> (unit - 1)) | ||||||
|  | 		codec.Size = -codec.Size | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	for codec.Size < 0 { | ||||||
|  | 		if codec.Ptr >= len(buffer) { | ||||||
|  | 			return ErrBufferInsufficient | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		codec.Size++ | ||||||
|  | 		*value = (*value << unit) | int64(buffer[codec.Ptr]) | ||||||
|  | 		codec.Ptr++ | ||||||
|  | 	} | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  | @ -0,0 +1,108 @@ | ||||||
|  | package encoding | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"fmt" | ||||||
|  | 	"testing" | ||||||
|  | 
 | ||||||
|  | 	"github.com/stretchr/testify/assert" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | func TestNInt32(t *testing.T) { | ||||||
|  | 	testNVarInt32(t, -1, []byte{0xFF}) | ||||||
|  | 	testNVarInt32(t, -5, []byte{0xFB}) | ||||||
|  | 	testNVarInt32(t, 63, []byte{0x3F}) | ||||||
|  | 	testNVarInt32(t, -65, []byte{0xBF}) | ||||||
|  | 	testNVarInt32(t, 127, []byte{0x7F}) | ||||||
|  | 	testNVarInt32(t, 255, []byte{0x00, 0xFF}) | ||||||
|  | 	testNVarInt32(t, -4097, []byte{0xEF, 0xFF}) | ||||||
|  | 	testNVarInt32(t, -8193, []byte{0xDF, 0xFF}) | ||||||
|  | 	testNVarInt32(t, -2097152, []byte{0xE0, 0x00, 0x00}) | ||||||
|  | 	testNVarInt32(t, -134217729, []byte{0xF7, 0xFF, 0xFF, 0xFF}) | ||||||
|  | 	testNVarInt32(t, -2147483648, []byte{0x80, 0x00, 0x00, 0x00}) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func TestNUInt32(t *testing.T) { | ||||||
|  | 	testNVarUInt32(t, 1, []byte{0x01}) | ||||||
|  | 	testNVarUInt32(t, 127, []byte{0x7F}) | ||||||
|  | 	testNVarUInt32(t, 128, []byte{0x00, 0x80}) | ||||||
|  | 	testNVarUInt32(t, 130, []byte{0x00, 0x82}) | ||||||
|  | 	testNVarUInt32(t, 1048576, []byte{0x10, 0x00, 0x00}) | ||||||
|  | 	testNVarUInt32(t, 134217728, []byte{0x08, 0x00, 0x00, 0x00}) | ||||||
|  | 	testNVarUInt32(t, 4294967295, []byte{0xFF}) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func TestNInt64(t *testing.T) { | ||||||
|  | 	testNVarInt64(t, 0, []byte{0x00}) | ||||||
|  | 	testNVarInt64(t, 1, []byte{0x01}) | ||||||
|  | 	testNVarInt64(t, -1, []byte{0xFF}) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func TestNUInt64(t *testing.T) { | ||||||
|  | 	testNVarUInt64(t, 0, []byte{0x00}) | ||||||
|  | 	testNVarUInt64(t, 1, []byte{0x01}) | ||||||
|  | 	testNVarUInt64(t, 18446744073709551615, []byte{0xFF}) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func testNVarInt32(t *testing.T, value int32, bytes []byte) { | ||||||
|  | 	var msg = fmt.Sprintf("tester %v (%X): %X", value, uint32(value), bytes) | ||||||
|  | 	var size = SizeOfNVarInt32(value) | ||||||
|  | 	assert.Equal(t, len(bytes), size, msg) | ||||||
|  | 
 | ||||||
|  | 	buffer := make([]byte, len(bytes)) | ||||||
|  | 	codec := VarCodec{Size: size} | ||||||
|  | 	assert.Nil(t, codec.EncodeNVarInt32(buffer, value), msg) | ||||||
|  | 	assert.Equal(t, bytes, buffer, msg) | ||||||
|  | 
 | ||||||
|  | 	var val int32 | ||||||
|  | 	codec = VarCodec{Size: len(bytes)} | ||||||
|  | 	assert.Nil(t, codec.DecodeNVarInt32(bytes, &val), msg) | ||||||
|  | 	assert.Equal(t, value, val, msg) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func testNVarUInt32(t *testing.T, value uint32, bytes []byte) { | ||||||
|  | 	var msg = fmt.Sprintf("tester %v (%X): %X", value, value, bytes) | ||||||
|  | 	var size = SizeOfNVarUInt32(value) | ||||||
|  | 	assert.Equal(t, len(bytes), size, msg) | ||||||
|  | 
 | ||||||
|  | 	buffer := make([]byte, len(bytes)) | ||||||
|  | 	codec := VarCodec{Size: size} | ||||||
|  | 	assert.Nil(t, codec.EncodeNVarUInt32(buffer, value), msg) | ||||||
|  | 	assert.Equal(t, bytes, buffer, msg) | ||||||
|  | 
 | ||||||
|  | 	var val uint32 | ||||||
|  | 	codec = VarCodec{Size: len(bytes)} | ||||||
|  | 	assert.Nil(t, codec.DecodeNVarUInt32(bytes, &val), msg) | ||||||
|  | 	assert.Equal(t, value, val, msg) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func testNVarInt64(t *testing.T, value int64, bytes []byte) { | ||||||
|  | 	var msg = fmt.Sprintf("tester %v (%X): %X", value, uint64(value), bytes) | ||||||
|  | 	var size = SizeOfNVarInt64(value) | ||||||
|  | 	assert.Equal(t, len(bytes), size, msg) | ||||||
|  | 
 | ||||||
|  | 	buffer := make([]byte, len(bytes)) | ||||||
|  | 	codec := VarCodec{Size: size} | ||||||
|  | 	assert.Nil(t, codec.EncodeNVarInt64(buffer, value), msg) | ||||||
|  | 	assert.Equal(t, bytes, buffer, msg) | ||||||
|  | 
 | ||||||
|  | 	var val int64 | ||||||
|  | 	codec = VarCodec{Size: len(bytes)} | ||||||
|  | 	assert.Nil(t, codec.DecodeNVarInt64(bytes, &val), msg) | ||||||
|  | 	assert.Equal(t, value, val, msg) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func testNVarUInt64(t *testing.T, value uint64, bytes []byte) { | ||||||
|  | 	var msg = fmt.Sprintf("tester %v (%X): %X", value, value, bytes) | ||||||
|  | 	var size = SizeOfNVarUInt64(value) | ||||||
|  | 	assert.Equal(t, len(bytes), size, msg) | ||||||
|  | 
 | ||||||
|  | 	buffer := make([]byte, len(bytes)) | ||||||
|  | 	codec := VarCodec{Size: size} | ||||||
|  | 	assert.Nil(t, codec.EncodeNVarUInt64(buffer, value), msg) | ||||||
|  | 	assert.Equal(t, bytes, buffer, msg) | ||||||
|  | 
 | ||||||
|  | 	var val uint64 | ||||||
|  | 	codec = VarCodec{Size: len(bytes)} | ||||||
|  | 	assert.Nil(t, codec.DecodeNVarUInt64(bytes, &val), msg) | ||||||
|  | 	assert.Equal(t, value, val) | ||||||
|  | } | ||||||
|  | @ -0,0 +1,27 @@ | ||||||
|  | package encoding | ||||||
|  | 
 | ||||||
|  | // EncodePVarBool encode value as PVarBool to buffer
 | ||||||
|  | func (codec *VarCodec) EncodePVarBool(buffer []byte, value bool) error { | ||||||
|  | 	tmp := int64(1) | ||||||
|  | 	if !value { | ||||||
|  | 		tmp = int64(0) | ||||||
|  | 	} | ||||||
|  | 	return codec.encodePVarInt(buffer, tmp) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // DecodePVarBool decode to value as PVarBool from buffer
 | ||||||
|  | func (codec *VarCodec) DecodePVarBool(buffer []byte, value *bool) error { | ||||||
|  | 	if len(buffer) == 0 { | ||||||
|  | 		*value = false | ||||||
|  | 		return nil | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	var tmp int64 | ||||||
|  | 	var err = codec.decodePVarInt(buffer, &tmp) | ||||||
|  | 	if tmp == 1 { | ||||||
|  | 		*value = true | ||||||
|  | 	} else { | ||||||
|  | 		*value = false | ||||||
|  | 	} | ||||||
|  | 	return err | ||||||
|  | } | ||||||
|  | @ -0,0 +1,29 @@ | ||||||
|  | package encoding | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"fmt" | ||||||
|  | 	"testing" | ||||||
|  | 
 | ||||||
|  | 	"github.com/stretchr/testify/assert" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | func TestPVarBool(t *testing.T) { | ||||||
|  | 	testPVarBool(t, true, []byte{0x01}) | ||||||
|  | 	testPVarBool(t, false, []byte{0x00}) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func testPVarBool(t *testing.T, value bool, bytes []byte) { | ||||||
|  | 	var msg = fmt.Sprintf("tester %v (%v): %X", value, value, bytes) | ||||||
|  | 	var size = SizeOfPVarUInt32(uint32(1)) | ||||||
|  | 	assert.Equal(t, len(bytes), size, msg) | ||||||
|  | 
 | ||||||
|  | 	buffer := make([]byte, len(bytes)) | ||||||
|  | 	codec := VarCodec{Size: size} | ||||||
|  | 	assert.Nil(t, codec.EncodePVarBool(buffer, value), msg) | ||||||
|  | 	assert.Equal(t, bytes, buffer, msg) | ||||||
|  | 
 | ||||||
|  | 	var val bool | ||||||
|  | 	codec = VarCodec{} | ||||||
|  | 	assert.Nil(t, codec.DecodePVarBool(bytes, &val), msg) | ||||||
|  | 	assert.Equal(t, value, val, msg) | ||||||
|  | } | ||||||
|  | @ -0,0 +1,147 @@ | ||||||
|  | package encoding | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"errors" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | // SizeOfPVarInt32 return the buffer size after encoding value as PVarInt32
 | ||||||
|  | func SizeOfPVarInt32(value int32) int { | ||||||
|  | 	return sizeOfPVarInt(int64(value), 32) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // EncodePVarInt32 encode value as PVarInt32 to buffer
 | ||||||
|  | func (codec *VarCodec) EncodePVarInt32(buffer []byte, value int32) error { | ||||||
|  | 	return codec.encodePVarInt(buffer, int64(value)) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // DecodePVarInt32 decode to value as PVarInt32 from buffer
 | ||||||
|  | func (codec *VarCodec) DecodePVarInt32(buffer []byte, value *int32) error { | ||||||
|  | 	var val = int64(*value) | ||||||
|  | 	var err = codec.decodePVarInt(buffer, &val) | ||||||
|  | 	*value = int32(val) | ||||||
|  | 	return err | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // SizeOfPVarUInt32 return the buffer size after encoding value as PVarUInt32
 | ||||||
|  | func SizeOfPVarUInt32(value uint32) int { | ||||||
|  | 	return sizeOfPVarInt(int64(int32(value)), 32) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // EncodePVarUInt32 encode value as PVarUInt32 to buffer
 | ||||||
|  | func (codec *VarCodec) EncodePVarUInt32(buffer []byte, value uint32) error { | ||||||
|  | 	return codec.encodePVarInt(buffer, int64(int32(value))) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // DecodePVarUInt32 decode to value as PVarUInt32 from buffer
 | ||||||
|  | func (codec *VarCodec) DecodePVarUInt32(buffer []byte, value *uint32) error { | ||||||
|  | 	var val = int64(int32(*value)) | ||||||
|  | 	var err = codec.decodePVarInt(buffer, &val) | ||||||
|  | 	*value = uint32(val) | ||||||
|  | 	return err | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // SizeOfPVarInt64 return the buffer size after encoding value as PVarInt64
 | ||||||
|  | func SizeOfPVarInt64(value int64) int { | ||||||
|  | 	return sizeOfPVarInt(value, 64) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // EncodePVarInt64 encode value as PVarInt64 to buffer
 | ||||||
|  | func (codec *VarCodec) EncodePVarInt64(buffer []byte, value int64) error { | ||||||
|  | 	return codec.encodePVarInt(buffer, value) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // DecodePVarInt64 decode to value as PVarInt64 from buffer
 | ||||||
|  | func (codec *VarCodec) DecodePVarInt64(buffer []byte, value *int64) error { | ||||||
|  | 	return codec.decodePVarInt(buffer, value) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // SizeOfPVarUInt64 return the buffer size after encoding value as PVarUInt64
 | ||||||
|  | func SizeOfPVarUInt64(value uint64) int { | ||||||
|  | 	return sizeOfPVarInt(int64(value), 64) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // EncodePVarUInt64 encode value as PVarUInt64 to buffer
 | ||||||
|  | func (codec *VarCodec) EncodePVarUInt64(buffer []byte, value uint64) error { | ||||||
|  | 	return codec.encodePVarInt(buffer, int64(value)) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // DecodePVarUInt64 decode to value as PVarUInt64 from buffer
 | ||||||
|  | func (codec *VarCodec) DecodePVarUInt64(buffer []byte, value *uint64) error { | ||||||
|  | 	var val = int64(*value) | ||||||
|  | 	var err = codec.decodePVarInt(buffer, &val) | ||||||
|  | 	*value = uint64(val) | ||||||
|  | 	return err | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func sizeOfPVarInt(value int64, width int) int { | ||||||
|  | 	const unit = 7 // bit width of encoding unit
 | ||||||
|  | 
 | ||||||
|  | 	var lead = value >> (width - 1) | ||||||
|  | 	for size := width / unit; size > 0; size-- { | ||||||
|  | 		var lookAhead = value >> (size*unit - 1) | ||||||
|  | 		if lookAhead != lead { | ||||||
|  | 			return size + 1 | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return 1 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (codec *VarCodec) encodePVarInt(buffer []byte, value int64) error { | ||||||
|  | 	if codec == nil || codec.Size == 0 { | ||||||
|  | 		return errors.New("nothing to encode") | ||||||
|  | 	} | ||||||
|  | 	if codec.Ptr >= len(buffer) { | ||||||
|  | 		return ErrBufferInsufficient | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	const unit = 7       // bit width of encoding unit
 | ||||||
|  | 	const more = -1 << 7 // continuation bits
 | ||||||
|  | 	for codec.Size > 1 { | ||||||
|  | 		codec.Size-- | ||||||
|  | 		var part = value >> (codec.Size * unit) | ||||||
|  | 
 | ||||||
|  | 		buffer[codec.Ptr] = byte(part | more) | ||||||
|  | 		codec.Ptr++ | ||||||
|  | 
 | ||||||
|  | 		if codec.Ptr >= len(buffer) { | ||||||
|  | 			return ErrBufferInsufficient | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	const mask = -1 ^ (-1 << unit) // mask for encoding unit
 | ||||||
|  | 	codec.Size = 0 | ||||||
|  | 	buffer[codec.Ptr] = byte(value & mask) | ||||||
|  | 	codec.Ptr++ | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (codec *VarCodec) decodePVarInt(buffer []byte, value *int64) error { | ||||||
|  | 	if codec == nil { | ||||||
|  | 		return errors.New("nothing to decode") | ||||||
|  | 	} | ||||||
|  | 	if codec.Ptr >= len(buffer) { | ||||||
|  | 		return ErrBufferInsufficient | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	const unit = 7 // bit width of encoding unit
 | ||||||
|  | 	if codec.Size == 0 { // initialize sign bit
 | ||||||
|  | 		const flag = 8 - unit // bit width for non-encoding bits
 | ||||||
|  | 		*value = int64(int8(buffer[codec.Ptr]) << flag >> unit) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	const mask = -1 ^ (-1 << unit) // mask for encoding unit
 | ||||||
|  | 	for { | ||||||
|  | 		var part = int8(buffer[codec.Ptr]) | ||||||
|  | 		codec.Ptr++ | ||||||
|  | 
 | ||||||
|  | 		codec.Size++ | ||||||
|  | 		*value = (*value << unit) | int64(mask & part) | ||||||
|  | 
 | ||||||
|  | 		if part >= 0 { // it's the last byte
 | ||||||
|  | 			return nil | ||||||
|  | 		} | ||||||
|  | 		if codec.Ptr >= len(buffer) { | ||||||
|  | 			return ErrBufferInsufficient | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | @ -0,0 +1,108 @@ | ||||||
|  | package encoding | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"fmt" | ||||||
|  | 	"testing" | ||||||
|  | 
 | ||||||
|  | 	"github.com/stretchr/testify/assert" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | func TestPInt32(t *testing.T) { | ||||||
|  | 	testPVarInt32(t, -1, []byte{0x7F}) | ||||||
|  | 	testPVarInt32(t, -5, []byte{0x7B}) | ||||||
|  | 	testPVarInt32(t, 63, []byte{0x3F}) | ||||||
|  | 	testPVarInt32(t, -65, []byte{0xFF, 0x3F}) | ||||||
|  | 	testPVarInt32(t, 127, []byte{0x80, 0x7F}) | ||||||
|  | 	testPVarInt32(t, 255, []byte{0x81, 0x7F}) | ||||||
|  | 	testPVarInt32(t, -4097, []byte{0xDF, 0x7F}) | ||||||
|  | 	testPVarInt32(t, -8193, []byte{0xFF, 0xBF, 0x7F}) | ||||||
|  | 	testPVarInt32(t, -2097152, []byte{0xFF, 0x80, 0x80, 0x00}) | ||||||
|  | 	testPVarInt32(t, -134217729, []byte{0xFF, 0xBF, 0xFF, 0xFF, 0x7F}) | ||||||
|  | 	testPVarInt32(t, -2147483648, []byte{0xF8, 0x80, 0x80, 0x80, 0x00}) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func TestPUInt32(t *testing.T) { | ||||||
|  | 	testPVarUInt32(t, 1, []byte{0x01}) | ||||||
|  | 	testPVarUInt32(t, 127, []byte{0x80, 0x7F}) | ||||||
|  | 	testPVarUInt32(t, 128, []byte{0x81, 0x00}) | ||||||
|  | 	testPVarUInt32(t, 130, []byte{0x81, 0x02}) | ||||||
|  | 	testPVarUInt32(t, 1048576, []byte{0x80, 0xC0, 0x80, 0x00}) | ||||||
|  | 	testPVarUInt32(t, 134217728, []byte{0x80, 0xC0, 0x80, 0x80, 0x00}) | ||||||
|  | 	testPVarUInt32(t, 4294967295, []byte{0x7F}) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func TestPInt64(t *testing.T) { | ||||||
|  | 	testPVarInt64(t, 0, []byte{0x00}) | ||||||
|  | 	testPVarInt64(t, 1, []byte{0x01}) | ||||||
|  | 	testPVarInt64(t, -1, []byte{0x7F}) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func TestPUInt64(t *testing.T) { | ||||||
|  | 	testPVarUInt64(t, 0, []byte{0x00}) | ||||||
|  | 	testPVarUInt64(t, 1, []byte{0x01}) | ||||||
|  | 	testPVarUInt64(t, 18446744073709551615, []byte{0x7F}) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func testPVarInt32(t *testing.T, value int32, bytes []byte) { | ||||||
|  | 	var msg = fmt.Sprintf("tester %v (%X): %X", value, uint32(value), bytes) | ||||||
|  | 	var size = SizeOfPVarInt32(value) | ||||||
|  | 	assert.Equal(t, len(bytes), size, msg) | ||||||
|  | 
 | ||||||
|  | 	buffer := make([]byte, len(bytes)) | ||||||
|  | 	codec := VarCodec{Size: size} | ||||||
|  | 	assert.Nil(t, codec.EncodePVarInt32(buffer, value), msg) | ||||||
|  | 	assert.Equal(t, bytes, buffer, msg) | ||||||
|  | 
 | ||||||
|  | 	var val int32 | ||||||
|  | 	codec = VarCodec{} | ||||||
|  | 	assert.Nil(t, codec.DecodePVarInt32(bytes, &val), msg) | ||||||
|  | 	assert.Equal(t, value, val, msg) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func testPVarUInt32(t *testing.T, value uint32, bytes []byte) { | ||||||
|  | 	var msg = fmt.Sprintf("tester %v (%X): %X", value, value, bytes) | ||||||
|  | 	var size = SizeOfPVarUInt32(value) | ||||||
|  | 	assert.Equal(t, len(bytes), size, msg) | ||||||
|  | 
 | ||||||
|  | 	buffer := make([]byte, len(bytes)) | ||||||
|  | 	codec := VarCodec{Size: size} | ||||||
|  | 	assert.Nil(t, codec.EncodePVarUInt32(buffer, value), msg) | ||||||
|  | 	assert.Equal(t, bytes, buffer, msg) | ||||||
|  | 
 | ||||||
|  | 	var val uint32 | ||||||
|  | 	codec = VarCodec{} | ||||||
|  | 	assert.Nil(t, codec.DecodePVarUInt32(bytes, &val), msg) | ||||||
|  | 	assert.Equal(t, value, val, msg) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func testPVarInt64(t *testing.T, value int64, bytes []byte) { | ||||||
|  | 	var msg = fmt.Sprintf("tester %v (%X): %X", value, uint64(value), bytes) | ||||||
|  | 	var size = SizeOfPVarInt64(value) | ||||||
|  | 	assert.Equal(t, len(bytes), size, msg) | ||||||
|  | 
 | ||||||
|  | 	buffer := make([]byte, len(bytes)) | ||||||
|  | 	codec := VarCodec{Size: size} | ||||||
|  | 	assert.Nil(t, codec.EncodePVarInt64(buffer, value), msg) | ||||||
|  | 	assert.Equal(t, bytes, buffer, msg) | ||||||
|  | 
 | ||||||
|  | 	var val int64 | ||||||
|  | 	codec = VarCodec{} | ||||||
|  | 	assert.Nil(t, codec.DecodePVarInt64(bytes, &val), msg) | ||||||
|  | 	assert.Equal(t, value, val, msg) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func testPVarUInt64(t *testing.T, value uint64, bytes []byte) { | ||||||
|  | 	var msg = fmt.Sprintf("tester %v (%X): %X", value, value, bytes) | ||||||
|  | 	var size = SizeOfPVarUInt64(value) | ||||||
|  | 	assert.Equal(t, len(bytes), size, msg) | ||||||
|  | 
 | ||||||
|  | 	buffer := make([]byte, len(bytes)) | ||||||
|  | 	codec := VarCodec{Size: size} | ||||||
|  | 	assert.Nil(t, codec.EncodePVarUInt64(buffer, value), msg) | ||||||
|  | 	assert.Equal(t, bytes, buffer, msg) | ||||||
|  | 
 | ||||||
|  | 	var val uint64 | ||||||
|  | 	codec = VarCodec{} | ||||||
|  | 	assert.Nil(t, codec.DecodePVarUInt64(bytes, &val), msg) | ||||||
|  | 	assert.Equal(t, value, val) | ||||||
|  | } | ||||||
|  | @ -0,0 +1,17 @@ | ||||||
|  | package encoding | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"errors" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | // ErrBufferInsufficient describes error when encode/decode malformed VarInt
 | ||||||
|  | var ErrBufferInsufficient = errors.New("buffer insufficient") | ||||||
|  | 
 | ||||||
|  | // VarCodec for encode/decode VarInt
 | ||||||
|  | type VarCodec struct { | ||||||
|  | 	// next ptr in buf
 | ||||||
|  | 	Ptr int | ||||||
|  | 	// Encoder: bytes are to be written,
 | ||||||
|  | 	// Decoder: bytes have been consumed
 | ||||||
|  | 	Size int | ||||||
|  | } | ||||||
|  | @ -0,0 +1,118 @@ | ||||||
|  | package encoding | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"errors" | ||||||
|  | 	"math" | ||||||
|  | 	mbit "math/bits" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | // SizeOfVarFloat32 return the buffer size after encoding value as VarFloat32
 | ||||||
|  | func SizeOfVarFloat32(value float32) int { | ||||||
|  | 	return sizeOfVarFloat(uint64(math.Float32bits(value)), 4) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // EncodeVarFloat32 encode value as VarFloat32 to buffer
 | ||||||
|  | func (codec *VarCodec) EncodeVarFloat32(buffer []byte, value float32) error { | ||||||
|  | 	return codec.encodeVarFloat(buffer, uint64(math.Float32bits(value)), 4) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // DecodeVarFloat32 decode to value as VarFloat32 from buffer
 | ||||||
|  | func (codec *VarCodec) DecodeVarFloat32(buffer []byte, value *float32) error { | ||||||
|  | 	var bits = uint64(math.Float32bits(*value)) | ||||||
|  | 	var err = codec.decodeVarFloat(buffer, &bits, 4) | ||||||
|  | 	*value = math.Float32frombits(uint32(bits)) | ||||||
|  | 	return err | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // SizeOfVarFloat64 return the buffer size after encoding value as VarFloat32
 | ||||||
|  | func SizeOfVarFloat64(value float64) int { | ||||||
|  | 	return sizeOfVarFloat(math.Float64bits(value), 8) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // EncodeVarFloat64 encode value as VarFloat64 to buffer
 | ||||||
|  | func (codec *VarCodec) EncodeVarFloat64(buffer []byte, value float64) error { | ||||||
|  | 	return codec.encodeVarFloat(buffer, math.Float64bits(value), 8) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // DecodeVarFloat64 decode to value as VarFloat64 from buffer
 | ||||||
|  | func (codec *VarCodec) DecodeVarFloat64(buffer []byte, value *float64) error { | ||||||
|  | 	var bits = math.Float64bits(*value) | ||||||
|  | 	var err = codec.decodeVarFloat(buffer, &bits, 8) | ||||||
|  | 	*value = math.Float64frombits(bits) | ||||||
|  | 	return err | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func sizeOfVarFloat(bits uint64, width int) int { | ||||||
|  | 	const unit = 8            // bit width of encoding unit
 | ||||||
|  | 	const mask = uint64(0xFF) // mask of encoding unit
 | ||||||
|  | 
 | ||||||
|  | 	for s := 0; width > 1; s += unit { | ||||||
|  | 		if bits & (mask << s) != 0 { | ||||||
|  | 			return width | ||||||
|  | 		} | ||||||
|  | 		width-- | ||||||
|  | 	} | ||||||
|  | 	return 1 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (codec *VarCodec) encodeVarFloat(buffer []byte, bits uint64, width int) error { | ||||||
|  | 	if codec == nil || codec.Size == 0 { | ||||||
|  | 		return errors.New("nothing to encode") | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	const unit = 8 // bit width of encoding unit
 | ||||||
|  | 	var gap, mask = codec.sizeOfGap(width) | ||||||
|  | 
 | ||||||
|  | 	for (codec.Size & mask) > 0 { | ||||||
|  | 		if codec.Ptr >= len(buffer) { | ||||||
|  | 			return ErrBufferInsufficient | ||||||
|  | 		} | ||||||
|  | 		codec.Size-- | ||||||
|  | 		buffer[codec.Ptr] = byte(bits >> ((codec.Size & mask + gap) * unit)) | ||||||
|  | 		codec.Ptr++ | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	codec.Size = 0 | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (codec *VarCodec) decodeVarFloat(buffer []byte, bits *uint64, width int) error { | ||||||
|  | 	if codec == nil || codec.Size == 0 { | ||||||
|  | 		return errors.New("nothing to decode") | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	const unit = 8 // bit width of encoding unit
 | ||||||
|  | 	var gap, mask = codec.sizeOfGap(width) | ||||||
|  | 
 | ||||||
|  | 	for (codec.Size & mask) > 0 { | ||||||
|  | 		if codec.Ptr >= len(buffer) { | ||||||
|  | 			return ErrBufferInsufficient | ||||||
|  | 		} | ||||||
|  | 		codec.Size-- | ||||||
|  | 		*bits = (*bits << unit) | uint64(buffer[codec.Ptr]) | ||||||
|  | 		codec.Ptr++ | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	*bits <<= gap * unit | ||||||
|  | 	codec.Size = 0 | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (codec *VarCodec) sizeOfGap(width int) (int, int) { | ||||||
|  | 	var ms = mbit.OnesCount(^uint(0)) // machine bit width for an int
 | ||||||
|  | 	var size = ms - 8                 // bit width of effective size
 | ||||||
|  | 	var mask = -1 ^ (-1 << size)      // mask of effective size
 | ||||||
|  | 
 | ||||||
|  | 	var gap = 0 // gap between encoded size and decoded size
 | ||||||
|  | 	if codec.Size > 0 { | ||||||
|  | 		if width > codec.Size { | ||||||
|  | 			gap = width - codec.Size | ||||||
|  | 		} | ||||||
|  | 		var sign = -1 << (ms - 1) // single sign bit for an int
 | ||||||
|  | 		codec.Size = sign | (gap << size) | (codec.Size & mask) | ||||||
|  | 	} else { | ||||||
|  | 		gap = (codec.Size >> size) & 0x7F | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return gap, mask | ||||||
|  | } | ||||||
|  | @ -0,0 +1,61 @@ | ||||||
|  | package encoding | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"fmt" | ||||||
|  | 	"math" | ||||||
|  | 	"testing" | ||||||
|  | 
 | ||||||
|  | 	"github.com/stretchr/testify/assert" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | func TestFloat32(t *testing.T) { | ||||||
|  | 	testVarFloat32(t, 0, []byte{0x00}) | ||||||
|  | 	testVarFloat32(t, 1, []byte{0x3F, 0x80}) | ||||||
|  | 	testVarFloat32(t, 25, []byte{0x41, 0xC8}) | ||||||
|  | 	testVarFloat32(t, -2, []byte{0xC0}) | ||||||
|  | 	testVarFloat32(t, 0.25, []byte{0x3E, 0x80}) | ||||||
|  | 	testVarFloat32(t, 0.375, []byte{0x3E, 0xC0}) | ||||||
|  | 	testVarFloat32(t, 12.375, []byte{0x41, 0x46}) | ||||||
|  | 	testVarFloat32(t, 68.123, []byte{0x42, 0x88, 0x3E, 0xFA}) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func TestFloat64(t *testing.T) { | ||||||
|  | 	testVarFloat64(t, 0, []byte{0x00}) | ||||||
|  | 	testVarFloat64(t, 1, []byte{0x3F, 0xF0}) | ||||||
|  | 	testVarFloat64(t, 2, []byte{0x40}) | ||||||
|  | 	testVarFloat64(t, 23, []byte{0x40, 0x37}) | ||||||
|  | 	testVarFloat64(t, -2, []byte{0xC0}) | ||||||
|  | 	testVarFloat64(t, 0.01171875, []byte{0x3F, 0x88}) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func testVarFloat32(t *testing.T, value float32, bytes []byte) { | ||||||
|  | 	var msg = fmt.Sprintf("tester %v (%X): %X", value, math.Float32bits(value), bytes) | ||||||
|  | 	var size = SizeOfVarFloat32(value) | ||||||
|  | 	assert.Equal(t, len(bytes), size, msg) | ||||||
|  | 
 | ||||||
|  | 	buffer := make([]byte, len(bytes)) | ||||||
|  | 	codec := VarCodec{Size: size} | ||||||
|  | 	assert.Nil(t, codec.EncodeVarFloat32(buffer, value), msg) | ||||||
|  | 	assert.Equal(t, bytes, buffer, msg) | ||||||
|  | 
 | ||||||
|  | 	var val float32 | ||||||
|  | 	codec = VarCodec{Size: len(bytes)} | ||||||
|  | 	assert.Nil(t, codec.DecodeVarFloat32(bytes, &val), msg) | ||||||
|  | 	assert.Equal(t, value, val, msg) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func testVarFloat64(t *testing.T, value float64, bytes []byte) { | ||||||
|  | 	var msg = fmt.Sprintf("tester %v (%X): %X", value, math.Float64bits(value), bytes) | ||||||
|  | 	var size = SizeOfVarFloat64(value) | ||||||
|  | 	assert.Equal(t, len(bytes), size, msg) | ||||||
|  | 
 | ||||||
|  | 	buffer := make([]byte, len(bytes)) | ||||||
|  | 	codec := VarCodec{Size: size} | ||||||
|  | 	assert.Nil(t, codec.EncodeVarFloat64(buffer, value), msg) | ||||||
|  | 	assert.Equal(t, bytes, buffer, msg) | ||||||
|  | 
 | ||||||
|  | 	var val float64 | ||||||
|  | 	codec = VarCodec{Size: len(bytes)} | ||||||
|  | 	assert.Nil(t, codec.DecodeVarFloat64(bytes, &val), msg) | ||||||
|  | 	assert.Equal(t, value, val, msg) | ||||||
|  | } | ||||||
|  | @ -0,0 +1,8 @@ | ||||||
|  | module mq_coder | ||||||
|  | 
 | ||||||
|  | go 1.18 | ||||||
|  | 
 | ||||||
|  | replace ( | ||||||
|  | 	git.hpds.cc/Component/mq_coder/encoding latest => target mq_coder/encoding | ||||||
|  | 	git.hpds.cc/Component/mq_coder/spec latest => target mq_coder/spec | ||||||
|  | ) | ||||||
|  | @ -0,0 +1,156 @@ | ||||||
|  | package mq_coder | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"bytes" | ||||||
|  | 	"io" | ||||||
|  | 
 | ||||||
|  | 	"git.hpds.cc/Component/mq_coder/encoding" | ||||||
|  | 	"git.hpds.cc/Component/mq_coder/spec" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | // StreamPacket implement the Packet interface.
 | ||||||
|  | type StreamPacket struct { | ||||||
|  | 	t         spec.T | ||||||
|  | 	l         spec.L | ||||||
|  | 	vbuf      []byte | ||||||
|  | 	vr        io.Reader | ||||||
|  | 	chunkMode bool | ||||||
|  | 	chunkSize int | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | var _ Packet = &StreamPacket{} | ||||||
|  | 
 | ||||||
|  | // SeqId returns the sequenceId of this packet
 | ||||||
|  | func (p *StreamPacket) SeqId() int { return p.t.Sid() } | ||||||
|  | 
 | ||||||
|  | // Size returns the size of whole packet.
 | ||||||
|  | func (p *StreamPacket) Size() int { | ||||||
|  | 	// T.Size + L.Size + V.Size
 | ||||||
|  | 	return p.t.Size() + p.l.Size() + p.l.VSize() | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // VSize returns the size of V.
 | ||||||
|  | func (p *StreamPacket) VSize() int { return p.l.VSize() } | ||||||
|  | 
 | ||||||
|  | // Bytes return the raw bytes of this packet. V will be absent if
 | ||||||
|  | // is in chunked mode
 | ||||||
|  | func (p *StreamPacket) Bytes() []byte { | ||||||
|  | 	buf := new(bytes.Buffer) | ||||||
|  | 	// the raw bytes of T and L
 | ||||||
|  | 	p.writeTL(buf) | ||||||
|  | 	// p.valbuf stores the raw bytes of V
 | ||||||
|  | 	buf.Write(p.vbuf) | ||||||
|  | 
 | ||||||
|  | 	return buf.Bytes() | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // VReader return an io.Reader which can be read as the content of V.
 | ||||||
|  | func (p *StreamPacket) VReader() io.Reader { | ||||||
|  | 	if !p.chunkMode { | ||||||
|  | 		return bytes.NewReader(p.vbuf) | ||||||
|  | 	} | ||||||
|  | 	return p.vr | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Reader return an io.Reader which can be read as the whole bytes of
 | ||||||
|  | // this packet. This function only available if this V of packet is in
 | ||||||
|  | // chunked mode.
 | ||||||
|  | func (p *StreamPacket) Reader() io.Reader { | ||||||
|  | 	if !p.chunkMode { | ||||||
|  | 		buf := new(bytes.Buffer) | ||||||
|  | 		buf.Write(p.t.Bytes()) | ||||||
|  | 		buf.Write(p.l.Bytes()) | ||||||
|  | 		buf.Write(p.vbuf) | ||||||
|  | 		return buf | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	buf := new(bytes.Buffer) | ||||||
|  | 	// T and L of this packet
 | ||||||
|  | 	p.writeTL(buf) | ||||||
|  | 	// V of this packet
 | ||||||
|  | 	buf.Write(p.vbuf) | ||||||
|  | 
 | ||||||
|  | 	return &chunkVReader{ | ||||||
|  | 		buf:        buf, | ||||||
|  | 		src:        p.vr, | ||||||
|  | 		totalSize:  p.Size(), | ||||||
|  | 		ChunkVSize: p.VSize(), | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // IsStreamMode returns a bool value indicates if the V of
 | ||||||
|  | // this packet is in stream mode
 | ||||||
|  | func (p *StreamPacket) IsStreamMode() bool { | ||||||
|  | 	return p.chunkMode | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // IsNodeMode returns a bool value indicates if this packet
 | ||||||
|  | // is node mode
 | ||||||
|  | func (p *StreamPacket) IsNodeMode() bool { | ||||||
|  | 	return p.t.IsNodeMode() | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // write the raw bytes of T and L to given buf
 | ||||||
|  | func (p *StreamPacket) writeTL(buf *bytes.Buffer) { | ||||||
|  | 	buf.Write(p.t.Bytes()) | ||||||
|  | 	buf.Write(p.l.Bytes()) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // BytesV return V as bytes
 | ||||||
|  | func (p *StreamPacket) BytesV() []byte { | ||||||
|  | 	return p.vbuf | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // UTF8StringV return V as utf-8 string
 | ||||||
|  | func (p *StreamPacket) UTF8StringV() string { | ||||||
|  | 	return string(p.vbuf) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Int32V return V as int32
 | ||||||
|  | func (p *StreamPacket) Int32V() (val int32, err error) { | ||||||
|  | 	codec := encoding.VarCodec{Size: len(p.vbuf)} | ||||||
|  | 	err = codec.DecodeNVarInt32(p.vbuf, &val) | ||||||
|  | 	return val, err | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // UInt32V return V as uint32
 | ||||||
|  | func (p *StreamPacket) UInt32V() (val uint32, err error) { | ||||||
|  | 	codec := encoding.VarCodec{Size: len(p.vbuf)} | ||||||
|  | 	err = codec.DecodeNVarUInt32(p.vbuf, &val) | ||||||
|  | 	return val, err | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Int64V return V as int64
 | ||||||
|  | func (p *StreamPacket) Int64V() (val int64, err error) { | ||||||
|  | 	codec := encoding.VarCodec{Size: len(p.vbuf)} | ||||||
|  | 	err = codec.DecodeNVarInt64(p.vbuf, &val) | ||||||
|  | 	return val, err | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // UInt64V return V as uint64
 | ||||||
|  | func (p *StreamPacket) UInt64V() (val uint64, err error) { | ||||||
|  | 	codec := encoding.VarCodec{Size: len(p.vbuf)} | ||||||
|  | 	err = codec.DecodeNVarUInt64(p.vbuf, &val) | ||||||
|  | 	return val, err | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Float32V return V as float32
 | ||||||
|  | func (p *StreamPacket) Float32V() (val float32, err error) { | ||||||
|  | 	codec := encoding.VarCodec{Size: len(p.vbuf)} | ||||||
|  | 	err = codec.DecodeVarFloat32(p.vbuf, &val) | ||||||
|  | 	return val, err | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Float64V return V as float64
 | ||||||
|  | func (p *StreamPacket) Float64V() (val float64, err error) { | ||||||
|  | 	codec := encoding.VarCodec{Size: len(p.vbuf)} | ||||||
|  | 	err = codec.DecodeVarFloat64(p.vbuf, &val) | ||||||
|  | 	return val, err | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // BoolV return V as bool
 | ||||||
|  | func (p *StreamPacket) BoolV() (val bool, err error) { | ||||||
|  | 	codec := encoding.VarCodec{Size: len(p.vbuf)} | ||||||
|  | 	err = codec.DecodePVarBool(p.vbuf, &val) | ||||||
|  | 	return val, err | ||||||
|  | } | ||||||
|  | @ -0,0 +1,26 @@ | ||||||
|  | package spec | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"errors" | ||||||
|  | 	"io" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | const ( | ||||||
|  | 	maxSeqID     = 0x3F | ||||||
|  | 	flagBitNode  = 0x80 | ||||||
|  | 	wipeFlagBits = 0x3F | ||||||
|  | 	msb          = 0x80 | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | var ( | ||||||
|  | 	errInvalidSeqID = errors.New("y3.Builder: SeqID should >= 0 and =< 0x3F") | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | func readByte(reader io.Reader) (byte, error) { | ||||||
|  | 	var b [1]byte | ||||||
|  | 	n, err := reader.Read(b[:]) | ||||||
|  | 	if n == 0 { | ||||||
|  | 		return 0x00, err | ||||||
|  | 	} | ||||||
|  | 	return b[0], err | ||||||
|  | } | ||||||
|  | @ -0,0 +1,27 @@ | ||||||
|  | @startuml | ||||||
|  | namespace spec { | ||||||
|  |     class L << (S,Aquamarine) >> { | ||||||
|  |         - buf []byte | ||||||
|  |         - size int | ||||||
|  |         - len int | ||||||
|  | 
 | ||||||
|  |         + Bytes() []byte | ||||||
|  |         + Size() int | ||||||
|  |         + VSize() int | ||||||
|  | 
 | ||||||
|  |     } | ||||||
|  |     class T << (S,Aquamarine) >> { | ||||||
|  |         + Sid() int | ||||||
|  |         + Bytes() []byte | ||||||
|  |         + IsNodeMode() bool | ||||||
|  |         + SetNodeMode(flag bool) | ||||||
|  |         + Size() int | ||||||
|  | 
 | ||||||
|  |     } | ||||||
|  |     class spec.T << (T, #FF7700) >>  { | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | "__builtin__.byte" #.. "spec.T" | ||||||
|  | @enduml | ||||||
|  | @ -0,0 +1,54 @@ | ||||||
|  | package spec | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"io" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | // T is the Tag in a TLV structure
 | ||||||
|  | type T byte | ||||||
|  | 
 | ||||||
|  | // NewT returns a T with sequenceID. If this packet contains other
 | ||||||
|  | // packets, this packet will be a "node packet", the T of this packet
 | ||||||
|  | // will set MSB to T.
 | ||||||
|  | func NewT(seqID int) (T, error) { | ||||||
|  | 	if seqID < 0 || seqID > maxSeqID { | ||||||
|  | 		return 0, errInvalidSeqID | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return T(seqID), nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Sid returns the sequenceID of this packet.
 | ||||||
|  | func (t T) Sid() int { | ||||||
|  | 	return int(t & wipeFlagBits) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Bytes returns raw bytes of T.
 | ||||||
|  | func (t T) Bytes() []byte { | ||||||
|  | 	return []byte{byte(t)} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // IsNodeMode will return true if this packet contains other packets.
 | ||||||
|  | // Otherwise return flase.
 | ||||||
|  | func (t T) IsNodeMode() bool { | ||||||
|  | 	return t&flagBitNode == flagBitNode | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // SetNodeMode will set T to indicates this packet contains
 | ||||||
|  | // other packets.
 | ||||||
|  | func (t *T) SetNodeMode(flag bool) { | ||||||
|  | 	if flag { | ||||||
|  | 		*t |= flagBitNode | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Size return the size of T raw bytes.
 | ||||||
|  | func (t T) Size() int { | ||||||
|  | 	return 1 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // ReadT read T from a bufio.Reader
 | ||||||
|  | func ReadT(rd io.Reader) (T, error) { | ||||||
|  | 	b, err := readByte(rd) | ||||||
|  | 	return T(b), err | ||||||
|  | } | ||||||
|  | @ -0,0 +1,90 @@ | ||||||
|  | package spec | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"bytes" | ||||||
|  | 	"errors" | ||||||
|  | 	"io" | ||||||
|  | 
 | ||||||
|  | 	//"git.hpds.cc/Component/mq_coder/encoding"
 | ||||||
|  | 	"mq_coder/encoding" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | // L is the Length in a TLV structure
 | ||||||
|  | type L struct { | ||||||
|  | 	buf  []byte | ||||||
|  | 	size int | ||||||
|  | 	len  int | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // NewL will take an int type len as parameter and return L to
 | ||||||
|  | // represent the size of V in a TLV. an integer will be encoded as
 | ||||||
|  | // a PVarInt32 type to represent the value.
 | ||||||
|  | func NewL(len int) (L, error) { | ||||||
|  | 	var l = L{} | ||||||
|  | 	if len < -1 { | ||||||
|  | 		return l, errors.New("y3.L: len can't less than -1") | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	valLen := int32(len) | ||||||
|  | 	l.size = encoding.SizeOfPVarInt32(valLen) | ||||||
|  | 	codec := encoding.VarCodec{Size: l.size} | ||||||
|  | 	tmp := make([]byte, l.size) | ||||||
|  | 	err := codec.EncodePVarInt32(tmp, valLen) | ||||||
|  | 	if err != nil { | ||||||
|  | 		panic(err) | ||||||
|  | 	} | ||||||
|  | 	l.buf = make([]byte, l.size) | ||||||
|  | 	copy(l.buf, tmp) | ||||||
|  | 	l.len = len | ||||||
|  | 	return l, nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Bytes will return the raw bytes of L.
 | ||||||
|  | func (l L) Bytes() []byte { | ||||||
|  | 	return l.buf | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Size returns how many bytes used to represent this L.
 | ||||||
|  | func (l L) Size() int { | ||||||
|  | 	return l.size | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // VSize returns the size of V.
 | ||||||
|  | func (l L) VSize() int { | ||||||
|  | 	return int(l.len) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // ReadL read L from bufio.Reader
 | ||||||
|  | func ReadL(r io.Reader) (*L, error) { | ||||||
|  | 	lenBuf := bytes.Buffer{} | ||||||
|  | 	for { | ||||||
|  | 		b, err := readByte(r) | ||||||
|  | 		if err != nil { | ||||||
|  | 			return nil, err | ||||||
|  | 		} | ||||||
|  | 		lenBuf.WriteByte(b) | ||||||
|  | 		if b&msb != msb { | ||||||
|  | 			break | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	buf := lenBuf.Bytes() | ||||||
|  | 
 | ||||||
|  | 	// decode to L
 | ||||||
|  | 	length, err := decodeL(buf) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return &L{ | ||||||
|  | 		buf:  buf, | ||||||
|  | 		len:  int(length), | ||||||
|  | 		size: len(buf), | ||||||
|  | 	}, nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func decodeL(buf []byte) (length int32, err error) { | ||||||
|  | 	codec := encoding.VarCodec{} | ||||||
|  | 	err = codec.DecodePVarInt32(buf, &length) | ||||||
|  | 	return length, err | ||||||
|  | } | ||||||
		Loading…
	
		Reference in New Issue