
for convenience. Signed-off-by: Izuru Yakumo <yakumo.izuru@chaotic.ninja> git-svn-id: file:///srv/svn/repo/suika/trunk@822 f0ae65fe-ee39-954e-97ec-027ff2717ef4
77 lines
1.9 KiB
Go
77 lines
1.9 KiB
Go
package bare
|
|
|
|
import (
|
|
"fmt"
|
|
"reflect"
|
|
)
|
|
|
|
// Any type which is a union member must implement this interface. You must
|
|
// also call RegisterUnion for go-bare to marshal or unmarshal messages which
|
|
// utilize your union type.
|
|
type Union interface {
|
|
IsUnion()
|
|
}
|
|
|
|
type UnionTags struct {
|
|
iface reflect.Type
|
|
tags map[reflect.Type]uint64
|
|
types map[uint64]reflect.Type
|
|
}
|
|
|
|
var unionInterface = reflect.TypeOf((*Union)(nil)).Elem()
|
|
var unionRegistry map[reflect.Type]*UnionTags
|
|
|
|
func init() {
|
|
unionRegistry = make(map[reflect.Type]*UnionTags)
|
|
}
|
|
|
|
// Registers a union type in this context. Pass the union interface and the
|
|
// list of types associated with it, sorted ascending by their union tag.
|
|
func RegisterUnion(iface interface{}) *UnionTags {
|
|
ity := reflect.TypeOf(iface).Elem()
|
|
if _, ok := unionRegistry[ity]; ok {
|
|
panic(fmt.Errorf("Type %s has already been registered", ity.Name()))
|
|
}
|
|
|
|
if !ity.Implements(reflect.TypeOf((*Union)(nil)).Elem()) {
|
|
panic(fmt.Errorf("Type %s does not implement bare.Union", ity.Name()))
|
|
}
|
|
|
|
utypes := &UnionTags{
|
|
iface: ity,
|
|
tags: make(map[reflect.Type]uint64),
|
|
types: make(map[uint64]reflect.Type),
|
|
}
|
|
unionRegistry[ity] = utypes
|
|
return utypes
|
|
}
|
|
|
|
func (ut *UnionTags) Member(t interface{}, tag uint64) *UnionTags {
|
|
ty := reflect.TypeOf(t)
|
|
if !ty.AssignableTo(ut.iface) {
|
|
panic(fmt.Errorf("Type %s does not implement interface %s",
|
|
ty.Name(), ut.iface.Name()))
|
|
}
|
|
if _, ok := ut.tags[ty]; ok {
|
|
panic(fmt.Errorf("Type %s is already registered for union %s",
|
|
ty.Name(), ut.iface.Name()))
|
|
}
|
|
if _, ok := ut.types[tag]; ok {
|
|
panic(fmt.Errorf("Tag %d is already registered for union %s",
|
|
tag, ut.iface.Name()))
|
|
}
|
|
ut.tags[ty] = tag
|
|
ut.types[tag] = ty
|
|
return ut
|
|
}
|
|
|
|
func (ut *UnionTags) TagFor(v interface{}) (uint64, bool) {
|
|
tag, ok := ut.tags[reflect.TypeOf(v)]
|
|
return tag, ok
|
|
}
|
|
|
|
func (ut *UnionTags) TypeFor(tag uint64) (reflect.Type, bool) {
|
|
t, ok := ut.types[tag]
|
|
return t, ok
|
|
}
|