Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 1 | // +build android |
| 2 | |
| 3 | package main |
| 4 | |
| 5 | import ( |
| 6 | "fmt" |
| 7 | "path" |
| 8 | "reflect" |
| 9 | "strings" |
| 10 | |
| 11 | // Imported IDLs. Please add a link to all IDLs you care about here, |
| 12 | // and add all interfaces you care about to the init() function below. |
| 13 | "veyron/examples/fortune" |
Srdjan Petrovic | 16683eb | 2014-05-19 17:31:34 -0700 | [diff] [blame] | 14 | "veyron2/ipc" |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 15 | ) |
| 16 | |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 17 | func init() { |
Srdjan Petrovic | 16683eb | 2014-05-19 17:31:34 -0700 | [diff] [blame] | 18 | registerInterface((*fortune.Fortune)(nil)) |
| 19 | registerInterface((*fortune.FortuneService)(nil)) |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 20 | } |
| 21 | |
Srdjan Petrovic | 16683eb | 2014-05-19 17:31:34 -0700 | [diff] [blame] | 22 | // A list of all registered argGetter-s. |
| 23 | var register map[string]*argGetter = make(map[string]*argGetter) |
| 24 | |
| 25 | // registerInterface registers the provided IDL client or server interface |
| 26 | // so that its methods' arguments can be created on-the-fly. |
| 27 | func registerInterface(ifacePtr interface{}) { |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 28 | t := reflect.TypeOf(ifacePtr) |
| 29 | if t.Kind() != reflect.Ptr { |
Srdjan Petrovic | 16683eb | 2014-05-19 17:31:34 -0700 | [diff] [blame] | 30 | panic(fmt.Sprintf("expected pointer type for %q, got: %v", ifacePtr, t.Kind())) |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 31 | } |
| 32 | t = t.Elem() |
| 33 | if t.Kind() != reflect.Interface { |
Srdjan Petrovic | 16683eb | 2014-05-19 17:31:34 -0700 | [diff] [blame] | 34 | panic(fmt.Sprintf("expected interface type for %q, got: %v", ifacePtr, t.Kind())) |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 35 | } |
| 36 | |
Srdjan Petrovic | 16683eb | 2014-05-19 17:31:34 -0700 | [diff] [blame] | 37 | // Create a new arg getter. |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 38 | methods := make(map[string][]methodInfo) |
| 39 | for i := 0; i < t.NumMethod(); i++ { |
| 40 | m := t.Method(i) |
Srdjan Petrovic | 16683eb | 2014-05-19 17:31:34 -0700 | [diff] [blame] | 41 | in := make([]reflect.Type, m.Type.NumIn()-1) |
| 42 | idx := 0 |
Matt Rosencrantz | f5afcaf | 2014-06-02 11:31:22 -0700 | [diff] [blame] | 43 | contextType := reflect.TypeOf((*ipc.ServerContext)(nil)).Elem() |
| 44 | optType := reflect.TypeOf((*ipc.CallOpt)(nil)).Elem() |
Srdjan Petrovic | 16683eb | 2014-05-19 17:31:34 -0700 | [diff] [blame] | 45 | for j := 0; j < m.Type.NumIn(); j++ { |
| 46 | argType := m.Type.In(j) |
| 47 | if j == 0 && argType == contextType { // skip the Context argument. |
| 48 | continue |
| 49 | } |
| 50 | if j == m.Type.NumIn()-1 && argType == optType { // skip the CallOption argument. |
| 51 | continue |
| 52 | } |
| 53 | in[idx] = argType |
| 54 | idx++ |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 55 | } |
| 56 | out := make([]reflect.Type, m.Type.NumOut()-1) // skip error argument |
| 57 | for j := 0; j < m.Type.NumOut()-1; j++ { |
| 58 | out[j] = m.Type.Out(j) |
| 59 | } |
| 60 | mis := methods[m.Name] |
| 61 | mis = append(mis, methodInfo{ |
| 62 | inTypes: in, |
| 63 | outTypes: out, |
| 64 | }) |
| 65 | methods[m.Name] = mis |
| 66 | } |
Srdjan Petrovic | 16683eb | 2014-05-19 17:31:34 -0700 | [diff] [blame] | 67 | path := path.Join(t.PkgPath(), t.Name()) |
| 68 | register[path] = &argGetter{ |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 69 | methods: methods, |
| 70 | idlPath: path, |
| 71 | } |
Srdjan Petrovic | 16683eb | 2014-05-19 17:31:34 -0700 | [diff] [blame] | 72 | } |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 73 | |
Srdjan Petrovic | 16683eb | 2014-05-19 17:31:34 -0700 | [diff] [blame] | 74 | // newPtrInstance returns the pointer to the new instance of the provided type. |
| 75 | func newPtrInstance(t reflect.Type) interface{} { |
| 76 | return reflect.New(t).Interface() |
| 77 | } |
| 78 | |
| 79 | // newArgGetter returns the argument getter for the provided IDL interface. |
| 80 | func newArgGetter(javaIdlIfacePath string) *argGetter { |
| 81 | return register[strings.Join(strings.Split(javaIdlIfacePath, ".")[1:], "/")] |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 82 | } |
| 83 | |
| 84 | // argGetter serves method arguments for a specific interface. |
| 85 | type argGetter struct { |
| 86 | methods map[string][]methodInfo |
| 87 | idlPath string |
| 88 | } |
| 89 | |
| 90 | // methodInfo contains argument type information for a method belonging to an interface. |
| 91 | type methodInfo struct { |
| 92 | inTypes []reflect.Type |
| 93 | outTypes []reflect.Type |
| 94 | } |
| 95 | |
| 96 | func (m methodInfo) String() string { |
| 97 | in := fmt.Sprintf("[%d]", len(m.inTypes)) |
| 98 | out := fmt.Sprintf("[%d]", len(m.outTypes)) |
| 99 | for _, t := range m.inTypes { |
| 100 | in = in + ", " + t.Name() |
| 101 | } |
| 102 | for _, t := range m.outTypes { |
| 103 | out = out + ", " + t.Name() |
| 104 | } |
| 105 | return fmt.Sprintf("(%s; %s)", in, out) |
| 106 | } |
| 107 | |
| 108 | // findMethod returns the method type information for the given method, or nil if |
| 109 | // the method doesn't exist. |
| 110 | func (ag *argGetter) findMethod(method string, numInArgs int) *methodInfo { |
| 111 | ms, ok := ag.methods[method] |
| 112 | if !ok { |
| 113 | return nil |
| 114 | } |
| 115 | var m *methodInfo |
| 116 | for _, mi := range ms { |
| 117 | if len(mi.inTypes) == numInArgs { |
| 118 | m = &mi |
| 119 | break |
| 120 | } |
| 121 | } |
| 122 | return m |
| 123 | } |
| 124 | |
| 125 | // GetInArgTypes returns types of all input arguments for the given method. |
| 126 | func (ag *argGetter) GetInArgTypes(method string, numInArgs int) ([]reflect.Type, error) { |
| 127 | m := ag.findMethod(method, numInArgs) |
| 128 | if m == nil { |
| 129 | return nil, fmt.Errorf("couldn't find method %q with %d args in path %s", method, numInArgs, ag.idlPath) |
| 130 | } |
| 131 | return m.inTypes, nil |
| 132 | } |
| 133 | |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 134 | // GenInArgPtrs returns pointers to instances of all input arguments for the given method. |
| 135 | func (ag *argGetter) GetInArgPtrs(method string, numInArgs int) (argptrs []interface{}, err error) { |
| 136 | m := ag.findMethod(method, numInArgs) |
| 137 | if m == nil { |
| 138 | return nil, fmt.Errorf("couldn't find method %q with %d args in path %s", method, numInArgs, ag.idlPath) |
| 139 | } |
| 140 | argptrs = make([]interface{}, len(m.inTypes)) |
| 141 | for i, arg := range m.inTypes { |
| 142 | argptrs[i] = newPtrInstance(arg) |
| 143 | } |
| 144 | return |
| 145 | } |
| 146 | |
| 147 | // GetOurArgTypes returns types of all output arguments for the given method. |
| 148 | func (ag *argGetter) GetOutArgTypes(method string, numInArgs int) ([]reflect.Type, error) { |
| 149 | m := ag.findMethod(method, numInArgs) |
| 150 | if m == nil { |
| 151 | return nil, fmt.Errorf("couldn't find method %q with %d args in path %s", method, numInArgs, ag.idlPath) |
| 152 | } |
| 153 | return m.outTypes, nil |
| 154 | } |
| 155 | |
Srdjan Petrovic | 16683eb | 2014-05-19 17:31:34 -0700 | [diff] [blame] | 156 | // GetOutArgPtrs returns pointers to instances of all output arguments for the given method. |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 157 | func (ag *argGetter) GetOutArgPtrs(method string, numInArgs int) (argptrs []interface{}, err error) { |
| 158 | m := ag.findMethod(method, numInArgs) |
| 159 | if m == nil { |
| 160 | return nil, fmt.Errorf("couldn't find method %q with %d args in path %s", method, numInArgs, ag.idlPath) |
| 161 | } |
| 162 | argptrs = make([]interface{}, len(m.outTypes)) |
| 163 | for i, arg := range m.outTypes { |
| 164 | argptrs[i] = newPtrInstance(arg) |
| 165 | } |
| 166 | return |
| 167 | } |
| 168 | |
| 169 | // argGetters is a cache of created argument getters, keyed by IDL interface path. |
| 170 | var argGetters map[string]*argGetter = make(map[string]*argGetter) |