go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/luciexe/build/reflect.go (about) 1 // Copyright 2020 The LUCI Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package build 16 17 import ( 18 "context" 19 "reflect" 20 21 "google.golang.org/protobuf/proto" 22 "google.golang.org/protobuf/reflect/protoreflect" 23 ) 24 25 var ( 26 ctxType = reflect.TypeOf((*context.Context)(nil)).Elem() 27 protoMessageType = reflect.TypeOf((*proto.Message)(nil)).Elem() 28 errorType = reflect.TypeOf((*error)(nil)).Elem() 29 ) 30 31 func cmpArgsProtoT(perr error, expected []reflect.Type, actual func(int) reflect.Type) (ret reflect.Type) { 32 for i, ex := range expected { 33 cur := actual(i) 34 if ex == protoMessageType { 35 if !cur.Implements(ex) { 36 panic(perr) 37 } 38 ret = cur 39 } else if cur != ex { 40 panic(perr) 41 } 42 } 43 return 44 } 45 46 func derefFnPtr(perr error, fnptr any, in, out []reflect.Type) (fn reflect.Value, msgT protoreflect.Message) { 47 val := reflect.ValueOf(fnptr) 48 if val.Kind() != reflect.Ptr { 49 panic(perr) 50 } 51 52 fn = val.Elem() 53 var protoType reflect.Type 54 55 fnT := fn.Type() 56 if fnT.Kind() != reflect.Func { 57 panic(perr) 58 } 59 60 if fnT.NumIn() != len(in) { 61 panic(perr) 62 } 63 if pT := cmpArgsProtoT(perr, in, fnT.In); pT != nil { 64 protoType = pT 65 } 66 67 if fnT.NumOut() != len(out) { 68 panic(perr) 69 } 70 if pT := cmpArgsProtoT(perr, out, fnT.Out); pT != nil { 71 protoType = pT 72 } 73 74 return fn, reflect.New(protoType.Elem()).Interface().(proto.Message).ProtoReflect() 75 }