blob: 41de699da089a4066f93d8e015384c7c9553266a [file] [log] [blame]
// Copyright (C) 2014 The Android Open Source Project
//
// 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 cyclic
import (
"fmt"
"android.googlesource.com/platform/tools/gpu/binary"
"android.googlesource.com/platform/tools/gpu/binary/registry"
)
// Encoder creates a binary.Encoder that writes to the supplied binary.Writer.
func Encoder(writer binary.Writer) binary.Encoder {
return &encoder{
Writer: writer,
objects: map[binary.Object]uint32{},
ids: map[binary.ID]uint32{},
}
}
// Decoder creates a binary.Decoder that reads from the provided binary.Reader.
func Decoder(reader binary.Reader) *decoder {
return &decoder{
Reader: reader,
Namespace: registry.Global,
objects: map[uint32]binary.Object{},
ids: map[uint32]binary.ID{},
}
}
type encoder struct {
binary.Writer
objects map[binary.Object]uint32
ids map[binary.ID]uint32
}
type decoder struct {
binary.Reader
Namespace *registry.Namespace
objects map[uint32]binary.Object
ids map[uint32]binary.ID
}
func (e *encoder) ID(id binary.ID) error {
if sid, found := e.ids[id]; found {
return e.Uint32(sid << 1)
} else {
sid = uint32(len(e.ids)) + 1
e.ids[id] = sid
if err := e.Uint32((sid << 1) | 1); err != nil {
return err
}
return e.Data(id[:])
}
}
func (d *decoder) ID() (binary.ID, error) {
id := binary.ID{}
v, err := d.Uint32()
if err != nil {
return id, err
}
sid := v >> 1
if (v & 1) != 0 {
err := d.Data(id[:])
d.ids[sid] = id
return id, err
}
id, found := d.ids[sid]
if !found {
fmt.Errorf("Unknown id sid %v", sid)
}
return id, nil
}
func (d *decoder) SkipID() error {
if v, err := d.Uint32(); err != nil {
return err
} else if (v & 1) != 0 {
return d.Skip(binary.IDSize)
}
return nil
}
func (e *encoder) Value(obj binary.Object) error { return obj.Class().Encode(e, obj) }
func (d *decoder) Value(obj binary.Object) error { return obj.Class().DecodeTo(d, obj) }
func (d *decoder) SkipValue(obj binary.Object) error { return obj.Class().Skip(d) }
func (e *encoder) Variant(obj binary.Object) error {
if obj == nil {
return e.ID(binary.ID{})
}
class := obj.Class()
if err := e.ID(class.ID()); err != nil {
return err
}
return class.Encode(e, obj)
}
func (d *decoder) Variant() (binary.Object, error) {
if id, err := d.ID(); err != nil {
return nil, err
} else if class := d.Namespace.Lookup(id); class == nil {
return nil, fmt.Errorf("Unknown type id %v", id)
} else {
return class.Decode(d)
}
}
func (d *decoder) SkipVariant() (binary.ID, error) {
if id, err := d.ID(); err != nil {
return id, err
} else if class := d.Namespace.Lookup(id); class == nil {
return id, fmt.Errorf("Unknown type id %v", id)
} else {
return id, class.Skip(d)
}
}
func (e *encoder) Object(obj binary.Object) error {
if obj == nil {
return e.Uint32(0)
}
if sid, found := e.objects[obj]; found {
return e.Uint32(sid << 1)
} else {
sid = uint32(len(e.objects)) + 1
e.objects[obj] = sid
if err := e.Uint32((sid << 1) | 1); err != nil {
return err
}
return e.Variant(obj)
}
}
func (d *decoder) Object() (binary.Object, error) {
v, err := d.Uint32()
if err != nil || v == 0 {
return nil, err
}
sid := v >> 1
decode := (v & 1) != 0
o, found := d.objects[sid]
switch {
case found && decode:
_, err := d.SkipVariant()
return o, err
case decode:
o, err = d.Variant()
d.objects[sid] = o
return o, err
case found:
return o, nil
default:
return nil, fmt.Errorf("Unknown object sid %v", sid)
}
}
func (d *decoder) SkipObject() (binary.ID, error) {
if v, err := d.Uint32(); err != nil {
return binary.ID{}, err
} else if (v & 1) == 0 {
sid := v >> 1
if sid == 0 {
return binary.ID{}, nil
} else if obj, found := d.objects[sid]; !found {
return binary.ID{}, fmt.Errorf("Unknown object sid %v", sid)
} else {
return obj.Class().ID(), nil
}
}
return d.SkipVariant()
}
func (d *decoder) Lookup(id binary.ID) binary.Class {
return d.Namespace.Lookup(id)
}