1
// Copyright 2012, 2013 Canonical Ltd.
2
// Licensed under the AGPLv3, see LICENCE file for details.
14
errorType = reflect.TypeOf((*error)(nil)).Elem()
15
stringType = reflect.TypeOf("")
19
typeMutex sync.RWMutex
20
typesByGoType = make(map[reflect.Type]*Type)
22
objTypeMutex sync.RWMutex
23
objTypesByGoType = make(map[reflect.Type]*ObjType)
26
var ErrMethodNotFound = errors.New("no such method")
28
// Type holds information about a type that implements RPC server methods,
29
// a root-level RPC type.
31
// root holds the root type.
34
// method maps from root-object method name to
35
// information about that method. The term "obtain"
36
// is because these methods obtain an object to
38
method map[string]*RootMethod
40
// discarded holds names of all discarded methods.
44
// MethodNames returns the names of all the root object
45
// methods on the receiving object.
46
func (r *Type) MethodNames() []string {
47
names := make([]string, 0, len(r.method))
48
for name := range r.method {
49
names = append(names, name)
55
// Method returns information on the method with the given name,
56
// or the zero Method and ErrMethodNotFound if there is no such method
57
// (the only possible error).
58
func (r *Type) Method(name string) (RootMethod, error) {
59
m, ok := r.method[name]
61
return RootMethod{}, ErrMethodNotFound
66
func (r *Type) DiscardedMethods() []string {
67
return append([]string(nil), r.discarded...)
70
// RootMethod holds information on a root-level method.
71
type RootMethod struct {
72
// Call invokes the method. The rcvr parameter must be
73
// the same type as the root object. The given id is passed
74
// as an argument to the method.
75
Call func(rcvr reflect.Value, id string) (reflect.Value, error)
77
// Methods holds RPC object-method information about
78
// objects returned from the above call.
82
// TypeOf returns information on all root-level RPC methods
83
// implemented by an object of the given Go type.
84
// If goType is nil, it returns nil.
85
func TypeOf(goType reflect.Type) *Type {
90
t := typesByGoType[goType]
96
defer typeMutex.Unlock()
97
t = typesByGoType[goType]
102
typesByGoType[goType] = t
106
// typeOf is like TypeOf but without the cache - it
107
// always allocates. Called with rootTypeMutex locked.
108
func typeOf(goType reflect.Type) *Type {
110
method: make(map[string]*RootMethod),
112
for i := 0; i < goType.NumMethod(); i++ {
113
m := goType.Method(i)
114
if m.PkgPath != "" || isKillMethod(m) {
115
// The Kill method gets a special exception because
116
// it fulfils the Killer interface which we're expecting,
117
// so it's not really discarded as such.
120
if o := newRootMethod(m); o != nil {
121
rm.method[m.Name] = o
123
rm.discarded = append(rm.discarded, m.Name)
129
func isKillMethod(m reflect.Method) bool {
130
return m.Name == "Kill" && m.Type.NumIn() == 1 && m.Type.NumOut() == 0
133
func newRootMethod(m reflect.Method) *RootMethod {
140
t.In(1) != stringType ||
141
t.Out(1) != errorType {
144
f := func(rcvr reflect.Value, id string) (r reflect.Value, err error) {
145
out := rcvr.Method(m.Index).Call([]reflect.Value{reflect.ValueOf(id)})
147
// Workaround LP 1251076.
148
// gccgo appears to get confused and thinks that out[1] is not nil when
149
// in fact it is an interface value of type error and value nil.
150
// This workaround solves the problem by leaving error as nil if in fact
151
// it was nil and causes no harm for gc because the predicates above
152
// assert that if out[1] is not nil, then it is an error type.
153
err, _ = out[1].Interface().(error)
160
ObjType: ObjTypeOf(t.Out(0)),
164
// ObjType holds information on RPC methods implemented on
166
type ObjType struct {
168
method map[string]*ObjMethod
172
func (t *ObjType) GoType() reflect.Type {
176
// Method returns information on the method with the given name,
177
// or the zero Method and ErrMethodNotFound if there is no such method
178
// (the only possible error).
179
func (t *ObjType) Method(name string) (ObjMethod, error) {
180
m, ok := t.method[name]
182
return ObjMethod{}, ErrMethodNotFound
187
// DiscardedMethods returns the names of all methods that cannot
188
// implement RPC calls because their type signature is inappropriate.
189
func (t *ObjType) DiscardedMethods() []string {
190
return append([]string(nil), t.discarded...)
193
// MethodNames returns the names of all the RPC methods
194
// defined on the type.
195
func (t *ObjType) MethodNames() []string {
196
names := make([]string, 0, len(t.method))
197
for name := range t.method {
198
names = append(names, name)
204
// ObjMethod holds information about an RPC method on an
205
// object returned by a root-level method.
206
type ObjMethod struct {
207
// Params holds the argument type of the method, or nil
208
// if there is no argument.
211
// Result holds the return type of the method, or nil
212
// if the method returns no value.
215
// Call calls the method with the given argument
216
// on the given receiver value. If the method does
217
// not return a value, the returned value will not be valid.
218
Call func(rcvr, arg reflect.Value) (reflect.Value, error)
221
// ObjTypeOf returns information on all RPC methods
222
// implemented by an object of the given Go type,
223
// as returned from a root-level method.
224
// If objType is nil, it returns nil.
225
func ObjTypeOf(objType reflect.Type) *ObjType {
230
methods := objTypesByGoType[objType]
231
objTypeMutex.RUnlock()
236
defer objTypeMutex.Unlock()
237
methods = objTypesByGoType[objType]
241
methods = objTypeOf(objType)
242
objTypesByGoType[objType] = methods
246
// objTypeOf is like ObjTypeOf but without the cache.
247
// Called with objTypeMutex locked.
248
func objTypeOf(goType reflect.Type) *ObjType {
250
method: make(map[string]*ObjMethod),
253
for i := 0; i < goType.NumMethod(); i++ {
254
m := goType.Method(i)
258
if objm := newMethod(m, goType.Kind()); objm != nil {
259
objType.method[m.Name] = objm
261
objType.discarded = append(objType.discarded, m.Name)
267
func newMethod(m reflect.Method, receiverKind reflect.Kind) *ObjMethod {
272
var assemble func(arg reflect.Value) []reflect.Value
273
// N.B. The method type has the receiver as its first argument
274
// unless the receiver is an interface.
275
receiverArgCount := 1
276
if receiverKind == reflect.Interface {
281
case t.NumIn() == 0+receiverArgCount:
283
assemble = func(arg reflect.Value) []reflect.Value {
286
case t.NumIn() == 1+receiverArgCount:
288
p.Params = t.In(receiverArgCount)
289
assemble = func(arg reflect.Value) []reflect.Value {
290
return []reflect.Value{arg}
297
case t.NumOut() == 0:
299
p.Call = func(rcvr, arg reflect.Value) (r reflect.Value, err error) {
300
rcvr.Method(m.Index).Call(assemble(arg))
303
case t.NumOut() == 1 && t.Out(0) == errorType:
305
p.Call = func(rcvr, arg reflect.Value) (r reflect.Value, err error) {
306
out := rcvr.Method(m.Index).Call(assemble(arg))
308
err = out[0].Interface().(error)
312
case t.NumOut() == 1:
315
p.Call = func(rcvr, arg reflect.Value) (reflect.Value, error) {
316
out := rcvr.Method(m.Index).Call(assemble(arg))
319
case t.NumOut() == 2 && t.Out(1) == errorType:
320
// Method(...) (R, error)
322
p.Call = func(rcvr, arg reflect.Value) (r reflect.Value, err error) {
323
out := rcvr.Method(m.Index).Call(assemble(arg))
326
err = out[1].Interface().(error)
333
// The parameters and return value must be of struct type.
334
if p.Params != nil && p.Params.Kind() != reflect.Struct {
337
if p.Result != nil && p.Result.Kind() != reflect.Struct {