e300e9c423
Make use of the github.com/abcum/bump package to efficiently encode and decode from and to byte slices, whilst at the same time using encoder and decoder pools, instead of creating a new buffer for each encoding / decoding process.
196 lines
3.9 KiB
Go
196 lines
3.9 KiB
Go
// Copyright © 2016 Abcum Ltd
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package keys
|
|
|
|
import (
|
|
"encoding/binary"
|
|
"math"
|
|
"time"
|
|
|
|
"github.com/abcum/bump"
|
|
)
|
|
|
|
type reader struct {
|
|
r *bump.Reader
|
|
}
|
|
|
|
func newReader() *reader {
|
|
return &reader{
|
|
r: bump.NewReader(nil),
|
|
}
|
|
}
|
|
|
|
func (r *reader) unread() {
|
|
|
|
}
|
|
|
|
func (r *reader) lookNext() (byt byte) {
|
|
byt, _ = r.r.PeekByte()
|
|
return
|
|
}
|
|
|
|
func (r *reader) readNext(exp byte) (fnd bool) {
|
|
if byt, _ := r.r.PeekByte(); byt == exp {
|
|
r.r.ReadByte()
|
|
return true
|
|
}
|
|
return false
|
|
}
|
|
|
|
func (r *reader) readSize(sze int) (byt []byte) {
|
|
byt, _ = r.r.ReadBytes(sze)
|
|
return byt
|
|
}
|
|
|
|
func (r *reader) readUpto(exp ...byte) (byt []byte) {
|
|
|
|
LOOP:
|
|
for {
|
|
|
|
bit, _ := r.r.ReadByte()
|
|
byt = append(byt, bit)
|
|
if bit != exp[0] {
|
|
continue
|
|
}
|
|
|
|
for j := 1; j < len(exp); j++ {
|
|
if r.readNext(exp[j]) {
|
|
byt = append(byt, bit)
|
|
continue
|
|
}
|
|
break LOOP
|
|
}
|
|
|
|
break
|
|
|
|
}
|
|
|
|
return byt[:len(byt)-len(exp)]
|
|
|
|
}
|
|
|
|
// --------------------------------------------------
|
|
// --------------------------------------------------
|
|
// --------------------------------------------------
|
|
// --------------------------------------------------
|
|
// --------------------------------------------------
|
|
|
|
func (r *reader) readAny() (val interface{}) {
|
|
return r.readUpto(bEND)
|
|
}
|
|
|
|
func (r *reader) readNull() (val interface{}) {
|
|
if r.readNext(bNIL) {
|
|
r.readNext(bEND)
|
|
}
|
|
return
|
|
}
|
|
|
|
func (r *reader) readTime() (val time.Time) {
|
|
if r.readNext(bTME) {
|
|
bin := r.readSize(8)
|
|
dec := binary.BigEndian.Uint64(bin)
|
|
val = time.Unix(0, int64(dec)).UTC()
|
|
r.readNext(bEND)
|
|
}
|
|
return
|
|
}
|
|
|
|
func (r *reader) readBool() (val bool) {
|
|
if r.readNext(bVAL) {
|
|
val = r.readNext(bVAL)
|
|
r.readNext(bEND)
|
|
}
|
|
return
|
|
}
|
|
|
|
func (r *reader) readBytes() (val []byte) {
|
|
if r.readNext(bSTR) {
|
|
val = r.readUpto(bEND, bEND)
|
|
}
|
|
return
|
|
}
|
|
|
|
func (r *reader) readFloat() (val float64) {
|
|
if r.readNext(bNEG) {
|
|
bin := r.readSize(8)
|
|
dec := binary.BigEndian.Uint64(bin)
|
|
val = math.Float64frombits(^dec)
|
|
r.readNext(bEND)
|
|
} else if r.readNext(bPOS) {
|
|
bin := r.readSize(8)
|
|
dec := binary.BigEndian.Uint64(bin)
|
|
val = math.Float64frombits(dec)
|
|
r.readNext(bEND)
|
|
}
|
|
return
|
|
}
|
|
|
|
func (r *reader) readString() (val string) {
|
|
if r.readNext(bSTR) {
|
|
val = string(r.readUpto(bEND, bEND))
|
|
} else if r.readNext(bPRE) {
|
|
val = Prefix
|
|
r.readNext(bEND)
|
|
} else if r.readNext(bSUF) {
|
|
val = Suffix
|
|
r.readNext(bEND)
|
|
}
|
|
return
|
|
}
|
|
|
|
func (r *reader) readNumber() (val interface{}) {
|
|
var num float64
|
|
if r.readNext(bNEG) {
|
|
bin := r.readSize(8)
|
|
dec := binary.BigEndian.Uint64(bin)
|
|
num = math.Float64frombits(^dec)
|
|
r.readNext(bEND)
|
|
} else if r.readNext(bPOS) {
|
|
bin := r.readSize(8)
|
|
dec := binary.BigEndian.Uint64(bin)
|
|
num = math.Float64frombits(dec)
|
|
r.readNext(bEND)
|
|
}
|
|
if math.Trunc(num) == num {
|
|
return int64(math.Trunc(num))
|
|
}
|
|
return num
|
|
}
|
|
|
|
func (r *reader) readArray() (val []interface{}) {
|
|
if r.readNext(bARR) {
|
|
for !r.readNext(bEND) {
|
|
switch r.lookNext() {
|
|
default:
|
|
val = append(val, []interface{}{r.readAny()}...)
|
|
case bNIL:
|
|
val = append(val, []interface{}{r.readNull()}...)
|
|
case bVAL:
|
|
val = append(val, []interface{}{r.readBool()}...)
|
|
case bTME:
|
|
val = append(val, []interface{}{r.readTime()}...)
|
|
case bNEG, bPOS:
|
|
val = append(val, []interface{}{r.readNumber()}...)
|
|
case bSTR, bPRE, bSUF:
|
|
val = append(val, []interface{}{r.readString()}...)
|
|
case bARR:
|
|
val = append(val, []interface{}{r.readArray()}...)
|
|
}
|
|
}
|
|
r.readNext(bEND)
|
|
}
|
|
return
|
|
}
|