blob: 68fbdf2333e4ff9200c57821c023bb637e107e35 [file] [log] [blame]
// Copyright 2015 The Vanadium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package vom
import (
"io"
"math"
)
// paddingLen must be large enough to hold the header in writeMsg.
const paddingLen = maxEncodedUintBytes * 2
func newSwitchedEncbuf(w io.Writer, version Version) *switchedEncbuf {
if version == Version80 {
return &switchedEncbuf{
version: version,
expanding: newEncbuf(int(math.MaxInt32)),
w: w,
}
} else {
return &switchedEncbuf{
version: version,
chunked: newChunkedEncbuf(w),
}
}
}
// switchedEncbuf switches between using chunkedEncbuf or encbuf on its own, depending on
// the version of VOM.
type switchedEncbuf struct {
version Version
expanding *encbuf
hasLen bool
mid int64
w io.Writer
chunked *chunkedEncbuf
}
func (b *switchedEncbuf) StartMessage(hasAnyOrTypeObject, hasLen, typeIncomplete bool, mid int64) error {
if b.version == Version80 {
b.expanding.Reset()
b.expanding.Grow(paddingLen)
b.hasLen = hasLen
b.mid = mid
return nil
} else {
return b.chunked.StartMessage(hasAnyOrTypeObject, hasLen, typeIncomplete, int(mid))
}
}
func (b *switchedEncbuf) FinishMessage() error {
if b.version == Version80 {
msg := b.expanding.Bytes()
header := msg[:paddingLen]
if b.hasLen {
start := binaryEncodeUintEnd(header, uint64(len(msg)-paddingLen))
header = header[:start]
}
// Note that we encode the negative id for type definitions.
start := binaryEncodeIntEnd(header, b.mid)
_, err := b.w.Write(msg[start:])
return err
} else {
return b.chunked.FinishMessage()
}
}
// Grow the buffer by n bytes, and returns those bytes.
//
// Different from bytes.Buffer.Grow, which doesn't return the bytes. Although
// this makes expandingEncbuf slightly easier to misuse, it helps to improve performance
// by avoiding unnecessary copying.
func (b *switchedEncbuf) Grow(n int) ([]byte, error) {
if b.version == Version80 {
return b.expanding.Grow(n), nil
} else {
return b.chunked.Grow(n)
}
}
// WriteByte writes byte c into the buffer.
func (b *switchedEncbuf) WriteOneByte(c byte) error {
if b.version == Version80 {
b.expanding.WriteOneByte(c)
return nil
} else {
return b.chunked.WriteOneByte(c)
}
}
// Write writes slice p into the buffer.
func (b *switchedEncbuf) Write(p []byte) error {
if b.version == Version80 {
// Should write the entire byte array.
b.expanding.WriteMaximumPossible(p)
return nil
} else {
return b.chunked.Write(p)
}
}
// WriteString writes string s into the buffer.
func (b *switchedEncbuf) WriteString(s string) error {
if b.version == Version80 {
// Should write the entire string.
b.expanding.WriteMaximumPossible([]byte(s))
return nil
} else {
return b.chunked.WriteString(s)
}
}
func (b *switchedEncbuf) ReferenceTypeID(typeID typeId) uint64 {
if b.version == Version80 {
panic("AddTypeID() does not apply to versions before 0x81")
}
return b.chunked.ReferenceTypeID(typeID)
}