blob: 67d867fa912cf466760e09e30efa6b8fceb0a9ae [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 (
"bytes"
"fmt"
"strconv"
"v.io/v23/vdl"
)
type RawBytes struct {
Version Version
Type *vdl.Type
RefTypes []*vdl.Type
AnyLengths []int
Data []byte
}
func (RawBytes) __VDLReflect(struct {
Type interface{} // ensure vdl.TypeOf(RawBytes{}) returns vdl.AnyType
}) {
}
func RawBytesOf(value interface{}) *RawBytes {
rb, err := RawBytesFromValue(value)
if err != nil {
panic(err)
}
return rb
}
func RawBytesFromValue(value interface{}) (*RawBytes, error) {
// TODO(bprosnitz) This implementation is temporary - we should make it faster
dat, err := Encode(value)
if err != nil {
return nil, err
}
var rb RawBytes
err = Decode(dat, &rb)
return &rb, err
}
// String outputs a string representation of RawBytes of the form
// RawBytes{Version81, int8, RefTypes{bool, string}, AnyLengths{4}, fa0e9dcc}
func (rb *RawBytes) String() string {
var buf bytes.Buffer
buf.WriteString("RawBytes{")
buf.WriteString(rb.Version.String())
buf.WriteString(", ")
buf.WriteString(rb.Type.String())
buf.WriteString(", ")
if len(rb.RefTypes) > 0 {
buf.WriteString("RefTypes{")
for i, t := range rb.RefTypes {
if i > 0 {
buf.WriteString(", ")
}
buf.WriteString(t.String())
}
buf.WriteString("}, ")
}
if len(rb.AnyLengths) > 0 {
buf.WriteString("AnyLengths{")
for i, l := range rb.AnyLengths {
if i > 0 {
buf.WriteString(", ")
}
buf.WriteString(strconv.Itoa(l))
}
buf.WriteString("}, ")
}
buf.WriteString(fmt.Sprintf("%x}", rb.Data))
return buf.String()
}
func (rb *RawBytes) ToValue(value interface{}) error {
// TODO(bprosnitz) This implementation is temporary - we should make it faster
dat, err := Encode(rb)
if err != nil {
return err
}
return Decode(dat, value)
}
func (rb *RawBytes) MakeVDLTarget() vdl.Target {
return &rbTarget{rb: rb}
}
func (rb *RawBytes) FillVDLTarget(target vdl.Target, _ *vdl.Type) error {
if rb == nil {
return vdl.FromValue(target, vdl.ZeroValue(vdl.AnyType))
}
var buf bytes.Buffer
enc := NewVersionedEncoder(rb.Version, &buf)
if err := enc.enc.encodeRaw(rb); err != nil {
return err
}
dec := NewDecoder(bytes.NewReader(buf.Bytes()))
return dec.decodeToTarget(target)
}
func (rb *RawBytes) IsNil() bool {
if rb == nil {
return true
}
if rb.Type != vdl.AnyType && rb.Type.Kind() != vdl.Optional {
return false
}
return len(rb.Data) == 1 && rb.Data[0] == WireCtrlNil
}
func (rb *RawBytes) Decoder() vdl.Decoder {
dec := NewDecoder(bytes.NewReader(rb.Data))
dec.buf.version = rb.Version
dec.refTypes.tids = make([]TypeId, len(rb.RefTypes))
for i, refType := range rb.RefTypes {
tid := TypeId(i) + WireIdFirstUserType
dec.typeDec.idToType[tid] = refType
dec.refTypes.tids[i] = tid
}
dec.refAnyLens.lens = make([]int, len(rb.AnyLengths))
for i, anyLen := range rb.AnyLengths {
dec.refAnyLens.lens[i] = anyLen
}
xd := &xDecoder{old: dec}
if err := xd.setupValue(rb.Type); err != nil {
panic(err)
}
xd.ignoreNextStartValue = true
return xd
}
func (rb *RawBytes) VDLIsZero() (bool, error) {
return rb == nil || (rb.Type == vdl.AnyType && rb.IsNil()), nil
}
func (rb *RawBytes) VDLRead(dec vdl.Decoder) error {
// Fastpath: the bytes are already available in the xDecoder. Note that this
// also handles the case where dec is RawBytes.Decoder().
if d, ok := dec.(*xDecoder); ok {
return d.readRawBytes(rb)
}
// Slowpath: the bytes are not available, we must encode new bytes.
return fmt.Errorf("vom: RawBytes.VDLRead slowpath not implemented")
}
func (rb *RawBytes) VDLWrite(enc vdl.Encoder) error {
if e, ok := enc.(*xEncoder); ok && e.version == rb.Version {
return e.writeRawBytes(rb)
}
return vdl.Transcode(enc, rb.Decoder())
}
// vdl.Target that writes to a vom.RawBytes. This structure is intended to be
// one-time-use and created via RawBytes.MakeVDLTarget.
type rbTarget struct {
rb *RawBytes // RawBytes to write to
enc *encoder // encoder to act as the underlying target
buf *bytes.Buffer // buffer of bytes written
startCount int // count the depth level of open calls, to determine when to write to rb
}
func (r *rbTarget) start(tt *vdl.Type) error {
r.startCount++
if r.startCount > 1 {
return nil
}
r.buf = bytes.NewBuffer(nil)
e := NewEncoder(r.buf)
r.enc = &e.enc
if _, err := r.enc.writer.Write([]byte{byte(r.enc.version)}); err != nil {
return err
}
r.enc.sentVersionByte = true
tid, err := r.enc.typeEnc.encode(tt)
if err != nil {
return err
}
if err := r.enc.startEncode(containsAny(tt), containsTypeObject(tt), hasChunkLen(tt), false, int64(tid)); err != nil {
return err
}
return nil
}
func (r *rbTarget) finish() error {
r.startCount--
if r.startCount > 0 {
return nil
}
if err := r.enc.finishEncode(); err != nil {
return err
}
err := Decode(r.buf.Bytes(), r.rb)
return err
}
func (r *rbTarget) FromBool(src bool, tt *vdl.Type) error {
if err := r.start(tt); err != nil {
return err
}
if err := r.enc.FromBool(src, tt); err != nil {
return err
}
return r.finish()
}
func (r *rbTarget) FromUint(src uint64, tt *vdl.Type) error {
if err := r.start(tt); err != nil {
return err
}
if err := r.enc.FromUint(src, tt); err != nil {
return err
}
return r.finish()
}
func (r *rbTarget) FromInt(src int64, tt *vdl.Type) error {
if err := r.start(tt); err != nil {
return err
}
if err := r.enc.FromInt(src, tt); err != nil {
return err
}
return r.finish()
}
func (r *rbTarget) FromFloat(src float64, tt *vdl.Type) error {
if err := r.start(tt); err != nil {
return err
}
if err := r.enc.FromFloat(src, tt); err != nil {
return err
}
return r.finish()
}
func (r *rbTarget) FromBytes(src []byte, tt *vdl.Type) error {
if err := r.start(tt); err != nil {
return err
}
if err := r.enc.FromBytes(src, tt); err != nil {
return err
}
return r.finish()
}
func (r *rbTarget) FromString(src string, tt *vdl.Type) error {
if err := r.start(tt); err != nil {
return err
}
if err := r.enc.FromString(src, tt); err != nil {
return err
}
return r.finish()
}
func (r *rbTarget) FromEnumLabel(src string, tt *vdl.Type) error {
if err := r.start(tt); err != nil {
return err
}
if err := r.enc.FromEnumLabel(src, tt); err != nil {
return err
}
return r.finish()
}
func (r *rbTarget) FromTypeObject(src *vdl.Type) error {
if err := r.start(vdl.TypeObjectType); err != nil {
return err
}
if err := r.enc.FromTypeObject(src); err != nil {
return err
}
return r.finish()
}
func (r *rbTarget) FromNil(tt *vdl.Type) error {
// TODO(bprosnitz) This is likely slow, look into optimizing it
if err := r.start(tt); err != nil {
return err
}
if err := r.enc.FromNil(tt); err != nil {
return err
}
return r.finish()
}
func (r *rbTarget) StartList(tt *vdl.Type, len int) (vdl.ListTarget, error) {
if err := r.start(tt); err != nil {
return nil, err
}
if _, err := r.enc.StartList(tt, len); err != nil {
return nil, err
}
return r, nil
}
func (r *rbTarget) FinishList(_ vdl.ListTarget) error {
if err := r.enc.FinishList(nil); err != nil {
return err
}
return r.finish()
}
func (r *rbTarget) StartSet(tt *vdl.Type, len int) (vdl.SetTarget, error) {
if err := r.start(tt); err != nil {
return nil, err
}
if _, err := r.enc.StartSet(tt, len); err != nil {
return nil, err
}
return r, nil
}
func (r *rbTarget) FinishSet(_ vdl.SetTarget) error {
if err := r.enc.FinishSet(nil); err != nil {
return err
}
return r.finish()
}
func (r *rbTarget) StartMap(tt *vdl.Type, len int) (vdl.MapTarget, error) {
if err := r.start(tt); err != nil {
return nil, err
}
if _, err := r.enc.StartMap(tt, len); err != nil {
return nil, err
}
return r, nil
}
func (r *rbTarget) FinishMap(_ vdl.MapTarget) error {
if err := r.enc.FinishMap(nil); err != nil {
return err
}
return r.finish()
}
func (r *rbTarget) StartFields(tt *vdl.Type) (vdl.FieldsTarget, error) {
if err := r.start(tt); err != nil {
return nil, err
}
if _, err := r.enc.StartFields(tt); err != nil {
return nil, err
}
return r, nil
}
func (r *rbTarget) FinishFields(_ vdl.FieldsTarget) error {
if err := r.enc.FinishFields(nil); err != nil {
return err
}
return r.finish()
}
func (r *rbTarget) StartElem(index int) (vdl.Target, error) {
if _, err := r.enc.StartElem(index); err != nil {
return nil, err
}
return r, nil
}
func (r *rbTarget) FinishElem(_ vdl.Target) error {
return r.enc.FinishElem(nil)
}
func (r *rbTarget) StartKey() (vdl.Target, error) {
if _, err := r.enc.StartKey(); err != nil {
return nil, err
}
return r, nil
}
func (r *rbTarget) FinishKey(_ vdl.Target) error {
return r.enc.FinishKey(nil)
}
func (r *rbTarget) FinishKeyStartField(_ vdl.Target) (vdl.Target, error) {
if _, err := r.enc.FinishKeyStartField(nil); err != nil {
return nil, err
}
return r, nil
}
func (r *rbTarget) StartField(key string) (vdl.Target, vdl.Target, error) {
if _, _, err := r.enc.StartField(key); err != nil {
return nil, nil, err
}
return r, r, nil
}
func (r *rbTarget) ZeroField(key string) error {
return r.enc.ZeroField(key)
}
func (r *rbTarget) FinishField(_, _ vdl.Target) error {
return r.enc.FinishField(nil, nil)
}