cborl/visitor.go (369 lines of code) (raw):

// Licensed to Elasticsearch B.V. under one or more contributor // license agreements. See the NOTICE file distributed with // this work for additional information regarding copyright // ownership. Elasticsearch B.V. licenses this file to you 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 cborl import ( "encoding/binary" "io" "math" structform "github.com/elastic/go-structform" ) type Visitor struct { w writer length lengthStack scratch [16]byte } type writer struct { out io.Writer } func (w writer) write(b []byte) error { _, err := w.out.Write(b) return err } func NewVisitor(out io.Writer) *Visitor { v := &Visitor{w: writer{out}} v.length.stack = v.length.stack0[:0] return v } func (vs *Visitor) writeByte(b byte) error { vs.scratch[0] = b return vs.w.write(vs.scratch[:1]) } func (vs *Visitor) OnObjectStart(len int, baseType structform.BaseType) error { if err := vs.optLen(majorMap, len); err != nil { return err } vs.length.push(int64(len)) return nil } func (vs *Visitor) OnObjectFinished() error { if vs.length.pop() < 0 { return vs.writeByte(codeBreak) } return nil } func (vs *Visitor) OnKey(s string) error { return vs.string(str2Bytes(s)) } func (vs *Visitor) OnKeyRef(s []byte) error { return vs.string(s) } func (vs *Visitor) OnArrayStart(len int, baseType structform.BaseType) error { if err := vs.optLen(majorArr, len); err != nil { return err } vs.length.push(int64(len)) return nil } func (vs *Visitor) OnArrayFinished() error { if vs.length.pop() < 0 { return vs.writeByte(codeBreak) } return nil } func (vs *Visitor) OnNil() error { return vs.writeByte(codeNull) } func (vs *Visitor) OnBool(b bool) error { if b { return vs.writeByte(codeTrue) } return vs.writeByte(codeFalse) } func (vs *Visitor) OnString(s string) error { return vs.string(str2Bytes(s)) } func (vs *Visitor) OnStringRef(s []byte) error { return vs.string(s) } func (vs *Visitor) OnInt8(i int8) error { return vs.int8(i) } func (vs *Visitor) OnInt16(i int16) error { return vs.int16(i) } func (vs *Visitor) OnInt32(i int32) error { return vs.int32(i) } func (vs *Visitor) OnInt64(i int64) error { return vs.int64(i) } func (vs *Visitor) OnInt(i int) error { return vs.int64(int64(i)) } func (vs *Visitor) OnByte(b byte) error { return vs.uint8(majorUint, b) } func (vs *Visitor) OnUint8(u uint8) error { return vs.uint8(majorUint, u) } func (vs *Visitor) OnUint16(u uint16) error { return vs.uint16(majorUint, u) } func (vs *Visitor) OnUint32(u uint32) error { return vs.uint32(majorUint, u) } func (vs *Visitor) OnUint64(u uint64) error { return vs.uint64(majorUint, u) } func (vs *Visitor) OnUint(u uint) error { return vs.uint64(majorUint, uint64(u)) } func (vs *Visitor) OnFloat32(f float32) error { b := math.Float32bits(f) vs.scratch[0] = codeSingleFloat binary.BigEndian.PutUint32(vs.scratch[1:5], b) return vs.w.write(vs.scratch[:5]) } func (vs *Visitor) OnFloat64(f float64) error { b := math.Float64bits(f) vs.scratch[0] = codeDoubleFloat binary.BigEndian.PutUint64(vs.scratch[1:9], b) return vs.w.write(vs.scratch[:9]) } func (vs *Visitor) OnBoolArray(a []bool) error { if err := vs.arrLen(len(a)); err != nil { return nil } for _, v := range a { if err := vs.OnBool(v); err != nil { return err } } return nil } func (vs *Visitor) OnStringArray(a []string) error { if err := vs.arrLen(len(a)); err != nil { return nil } for _, v := range a { if err := vs.OnString(v); err != nil { return err } } return nil } func (vs *Visitor) OnInt8Array(a []int8) error { if err := vs.arrLen(len(a)); err != nil { return nil } for _, v := range a { if err := vs.OnInt8(v); err != nil { return err } } return nil } func (vs *Visitor) OnInt16Array(a []int16) error { if err := vs.arrLen(len(a)); err != nil { return nil } for _, v := range a { if err := vs.OnInt16(v); err != nil { return err } } return nil } func (vs *Visitor) OnInt32Array(a []int32) error { if err := vs.arrLen(len(a)); err != nil { return nil } for _, v := range a { if err := vs.OnInt32(v); err != nil { return err } } return nil } func (vs *Visitor) OnInt64Array(a []int64) error { if err := vs.arrLen(len(a)); err != nil { return nil } for _, v := range a { if err := vs.OnInt64(v); err != nil { return err } } return nil } func (vs *Visitor) OnIntArray(a []int) error { if err := vs.arrLen(len(a)); err != nil { return nil } for _, v := range a { if err := vs.OnInt(v); err != nil { return err } } return nil } func (vs *Visitor) OnBytes(a []byte) error { return vs.bytes(majorBytes, a) } func (vs *Visitor) OnUint8Array(a []uint8) error { return vs.bytes(majorBytes, a) } func (vs *Visitor) OnUint16Array(a []uint16) error { if err := vs.arrLen(len(a)); err != nil { return nil } for _, v := range a { if err := vs.OnUint16(v); err != nil { return err } } return nil } func (vs *Visitor) OnUint32Array(a []uint32) error { if err := vs.arrLen(len(a)); err != nil { return nil } for _, v := range a { if err := vs.OnUint32(v); err != nil { return err } } return nil } func (vs *Visitor) OnUint64Array(a []uint64) error { if err := vs.arrLen(len(a)); err != nil { return nil } for _, v := range a { if err := vs.OnUint64(v); err != nil { return err } } return nil } func (vs *Visitor) OnUintArray(a []uint) error { if err := vs.arrLen(len(a)); err != nil { return nil } for _, v := range a { if err := vs.OnUint(v); err != nil { return err } } return nil } func (vs *Visitor) OnFloat32Array(a []float32) error { if err := vs.arrLen(len(a)); err != nil { return nil } for _, v := range a { if err := vs.OnFloat32(v); err != nil { return err } } return nil } func (vs *Visitor) OnFloat64Array(a []float64) error { if err := vs.arrLen(len(a)); err != nil { return nil } for _, v := range a { if err := vs.OnFloat64(v); err != nil { return err } } return nil } func (vs *Visitor) string(s []byte) error { return vs.bytes(majorText, s) } func (vs *Visitor) bytes(major uint8, buf []byte) error { if err := vs.uint64(major, uint64(len(buf))); err != nil { return err } return vs.w.write(buf) } func (vs *Visitor) arrLen(len int) error { return vs.uint64(majorArr, uint64(len)) } func (vs *Visitor) optLen(major uint8, len int) error { if len < 0 { return vs.writeByte(major | lenIndef) } return vs.uint64(major, uint64(len)) } func (vs *Visitor) int8(v int8) error { if v < 0 { return vs.uint8(majorNeg, ^uint8(v)) } return vs.uint8(majorUint, uint8(v)) } func (vs *Visitor) int16(v int16) error { if v < 0 { return vs.uint16(majorNeg, ^uint16(v)) } return vs.uint16(majorUint, uint16(v)) } func (vs *Visitor) int32(v int32) error { if v < 0 { return vs.uint32(majorNeg, ^uint32(v)) } return vs.uint32(majorUint, uint32(v)) } func (vs *Visitor) int64(v int64) error { if v < 0 { return vs.uint64(majorNeg, ^uint64(v)) } return vs.uint64(majorUint, uint64(v)) } func (vs *Visitor) uint8(major uint8, v uint8) error { if v < len8b { return vs.writeByte(major | v) } vs.scratch[0], vs.scratch[1] = major|len8b, v return vs.w.write(vs.scratch[:2]) } func (vs *Visitor) uint16(major uint8, v uint16) error { switch { case v < uint16(len8b): return vs.writeByte(major | uint8(v)) case v <= math.MaxUint8: vs.scratch[0], vs.scratch[1] = major|len8b, uint8(v) return vs.w.write(vs.scratch[:2]) default: vs.scratch[0] = major | len16b binary.BigEndian.PutUint16(vs.scratch[1:3], v) return vs.w.write(vs.scratch[:3]) } } func (vs *Visitor) uint32(major uint8, v uint32) error { switch { case v < uint32(len8b): return vs.writeByte(major | uint8(v)) case v <= math.MaxUint8: vs.scratch[0], vs.scratch[1] = major|len8b, uint8(v) return vs.w.write(vs.scratch[:2]) case v <= math.MaxUint16: vs.scratch[0] = major | len16b binary.BigEndian.PutUint16(vs.scratch[1:3], uint16(v)) return vs.w.write(vs.scratch[:3]) default: vs.scratch[0] = major | len32b binary.BigEndian.PutUint32(vs.scratch[1:5], v) return vs.w.write(vs.scratch[:5]) } } func (vs *Visitor) uint64(major uint8, v uint64) error { switch { case v < uint64(len8b): return vs.writeByte(major | uint8(v)) case v <= math.MaxUint8: vs.scratch[0], vs.scratch[1] = major|len8b, uint8(v) return vs.w.write(vs.scratch[:2]) case v <= math.MaxUint16: vs.scratch[0] = major | len16b binary.BigEndian.PutUint16(vs.scratch[1:3], uint16(v)) return vs.w.write(vs.scratch[:3]) case v <= math.MaxUint32: vs.scratch[0] = major | len32b binary.BigEndian.PutUint32(vs.scratch[1:5], uint32(v)) return vs.w.write(vs.scratch[:5]) default: vs.scratch[0] = major | len64b binary.BigEndian.PutUint64(vs.scratch[1:9], uint64(v)) return vs.w.write(vs.scratch[:9]) } }