blob: bff4842d8ab4f8c3b116b425c39a1b2991c7c1d7 [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 binary
import (
"fmt"
"reflect"
)
// Used as an object key to define a nil pointer
const objectNil uint16 = ^uint16(0)
type Encodable interface {
// Encode the object's data to the Encoder.
// The implementation must be symmetrical to Decode.
Encode(e *Encoder) error
}
type Decodable interface {
// Decode the object's data from the Decoder.
// The implementation must be symmetrical to Encode.
Decode(d *Decoder) error
}
type Object interface {
Encodable
Decodable
}
var (
typeToID = map[reflect.Type]ID{}
idToType = map[ID]reflect.Type{}
)
// Register adds a new type to the binary encoding system.
// The id should be a sha1 has of the types signature, such that
// no two types generate the same ID, and any change to a types name or
// fields causes it's signature to change.
func Register(id ID, instance Object) {
t := reflect.TypeOf(instance)
if oldId, found := typeToID[t]; found {
panic(fmt.Errorf("Type %s as %x already has id %x", t, id, oldId))
}
typeToID[t] = id
if oldType, found := idToType[id]; found {
panic(fmt.Errorf("Id %x for %s already as type %s", id, t, oldType))
}
idToType[id] = t.Elem()
}
type unknownType struct {
Object Encodable
}
func (e unknownType) Error() string {
return fmt.Sprintf("Unknown type %T encountered in binary.TypeOf", e.Object)
}
// Given an encodable object return the ID for that type of object.
// If there is no ID for this type of object, return a non-nil error.
func TypeOf(obj Encodable) (ID, error) {
id, idFound := typeToID[reflect.TypeOf(obj)]
if !idFound {
return ID{}, unknownType{obj}
}
return id, nil
}
type unknownTypeID ID
func (e unknownTypeID) Error() string {
return fmt.Sprintf("Unknown type id %v encountered in binary.MakeObject", ID(e))
}
// Given an ID return a zero value instance of the object type.
// If this ID is not for a registered type, return a non-nil error.
func MakeObject(typeId ID) (Decodable, error) {
t, idFound := idToType[typeId]
if !idFound {
return nil, unknownTypeID(typeId)
}
return reflect.New(t).Interface().(Decodable), nil
}