blob: 25c20035a9c26a2aae341f84c54b31340be5e90d [file] [log] [blame]
// +build android
package main
import (
"fmt"
"path"
"reflect"
"strings"
// Imported IDLs. Please add a link to all IDLs you care about here,
// and add all interfaces you care about to the init() function below.
"veyron/examples/fortune"
"veyron2/ipc"
)
func init() {
registerInterface((*fortune.Fortune)(nil))
registerInterface((*fortune.FortuneService)(nil))
}
// A list of all registered argGetter-s.
var register map[string]*argGetter = make(map[string]*argGetter)
// registerInterface registers the provided IDL client or server interface
// so that its methods' arguments can be created on-the-fly.
func registerInterface(ifacePtr interface{}) {
t := reflect.TypeOf(ifacePtr)
if t.Kind() != reflect.Ptr {
panic(fmt.Sprintf("expected pointer type for %q, got: %v", ifacePtr, t.Kind()))
}
t = t.Elem()
if t.Kind() != reflect.Interface {
panic(fmt.Sprintf("expected interface type for %q, got: %v", ifacePtr, t.Kind()))
}
// Create a new arg getter.
methods := make(map[string][]methodInfo)
for i := 0; i < t.NumMethod(); i++ {
m := t.Method(i)
in := make([]reflect.Type, m.Type.NumIn()-1)
idx := 0
contextType := reflect.TypeOf((*ipc.ServerContext)(nil)).Elem()
optType := reflect.TypeOf((*ipc.CallOpt)(nil)).Elem()
for j := 0; j < m.Type.NumIn(); j++ {
argType := m.Type.In(j)
if j == 0 && argType == contextType { // skip the Context argument.
continue
}
if j == m.Type.NumIn()-1 && argType == optType { // skip the CallOption argument.
continue
}
in[idx] = argType
idx++
}
out := make([]reflect.Type, m.Type.NumOut()-1) // skip error argument
for j := 0; j < m.Type.NumOut()-1; j++ {
out[j] = m.Type.Out(j)
}
mis := methods[m.Name]
mis = append(mis, methodInfo{
inTypes: in,
outTypes: out,
})
methods[m.Name] = mis
}
path := path.Join(t.PkgPath(), t.Name())
register[path] = &argGetter{
methods: methods,
idlPath: path,
}
}
// newPtrInstance returns the pointer to the new instance of the provided type.
func newPtrInstance(t reflect.Type) interface{} {
return reflect.New(t).Interface()
}
// newArgGetter returns the argument getter for the provided IDL interface.
func newArgGetter(javaIdlIfacePath string) *argGetter {
return register[strings.Join(strings.Split(javaIdlIfacePath, ".")[1:], "/")]
}
// argGetter serves method arguments for a specific interface.
type argGetter struct {
methods map[string][]methodInfo
idlPath string
}
// methodInfo contains argument type information for a method belonging to an interface.
type methodInfo struct {
inTypes []reflect.Type
outTypes []reflect.Type
}
func (m methodInfo) String() string {
in := fmt.Sprintf("[%d]", len(m.inTypes))
out := fmt.Sprintf("[%d]", len(m.outTypes))
for _, t := range m.inTypes {
in = in + ", " + t.Name()
}
for _, t := range m.outTypes {
out = out + ", " + t.Name()
}
return fmt.Sprintf("(%s; %s)", in, out)
}
// findMethod returns the method type information for the given method, or nil if
// the method doesn't exist.
func (ag *argGetter) findMethod(method string, numInArgs int) *methodInfo {
ms, ok := ag.methods[method]
if !ok {
return nil
}
var m *methodInfo
for _, mi := range ms {
if len(mi.inTypes) == numInArgs {
m = &mi
break
}
}
return m
}
// GetInArgTypes returns types of all input arguments for the given method.
func (ag *argGetter) GetInArgTypes(method string, numInArgs int) ([]reflect.Type, error) {
m := ag.findMethod(method, numInArgs)
if m == nil {
return nil, fmt.Errorf("couldn't find method %q with %d args in path %s", method, numInArgs, ag.idlPath)
}
return m.inTypes, nil
}
// GenInArgPtrs returns pointers to instances of all input arguments for the given method.
func (ag *argGetter) GetInArgPtrs(method string, numInArgs int) (argptrs []interface{}, err error) {
m := ag.findMethod(method, numInArgs)
if m == nil {
return nil, fmt.Errorf("couldn't find method %q with %d args in path %s", method, numInArgs, ag.idlPath)
}
argptrs = make([]interface{}, len(m.inTypes))
for i, arg := range m.inTypes {
argptrs[i] = newPtrInstance(arg)
}
return
}
// GetOurArgTypes returns types of all output arguments for the given method.
func (ag *argGetter) GetOutArgTypes(method string, numInArgs int) ([]reflect.Type, error) {
m := ag.findMethod(method, numInArgs)
if m == nil {
return nil, fmt.Errorf("couldn't find method %q with %d args in path %s", method, numInArgs, ag.idlPath)
}
return m.outTypes, nil
}
// GetOutArgPtrs returns pointers to instances of all output arguments for the given method.
func (ag *argGetter) GetOutArgPtrs(method string, numInArgs int) (argptrs []interface{}, err error) {
m := ag.findMethod(method, numInArgs)
if m == nil {
return nil, fmt.Errorf("couldn't find method %q with %d args in path %s", method, numInArgs, ag.idlPath)
}
argptrs = make([]interface{}, len(m.outTypes))
for i, arg := range m.outTypes {
argptrs[i] = newPtrInstance(arg)
}
return
}
// argGetters is a cache of created argument getters, keyed by IDL interface path.
var argGetters map[string]*argGetter = make(map[string]*argGetter)