1// Copyright 2018 The Go Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style 3// license that can be found in the LICENSE file. 4 5package impl 6 7import ( 8 "fmt" 9 "reflect" 10 11 "google.golang.org/protobuf/reflect/protoreflect" 12) 13 14func newListConverter(t reflect.Type, fd protoreflect.FieldDescriptor) Converter { 15 switch { 16 case t.Kind() == reflect.Ptr && t.Elem().Kind() == reflect.Slice: 17 return &listPtrConverter{t, newSingularConverter(t.Elem().Elem(), fd)} 18 case t.Kind() == reflect.Slice: 19 return &listConverter{t, newSingularConverter(t.Elem(), fd)} 20 } 21 panic(fmt.Sprintf("invalid Go type %v for field %v", t, fd.FullName())) 22} 23 24type listConverter struct { 25 goType reflect.Type // []T 26 c Converter 27} 28 29func (c *listConverter) PBValueOf(v reflect.Value) protoreflect.Value { 30 if v.Type() != c.goType { 31 panic(fmt.Sprintf("invalid type: got %v, want %v", v.Type(), c.goType)) 32 } 33 pv := reflect.New(c.goType) 34 pv.Elem().Set(v) 35 return protoreflect.ValueOfList(&listReflect{pv, c.c}) 36} 37 38func (c *listConverter) GoValueOf(v protoreflect.Value) reflect.Value { 39 rv := v.List().(*listReflect).v 40 if rv.IsNil() { 41 return reflect.Zero(c.goType) 42 } 43 return rv.Elem() 44} 45 46func (c *listConverter) IsValidPB(v protoreflect.Value) bool { 47 list, ok := v.Interface().(*listReflect) 48 if !ok { 49 return false 50 } 51 return list.v.Type().Elem() == c.goType 52} 53 54func (c *listConverter) IsValidGo(v reflect.Value) bool { 55 return v.IsValid() && v.Type() == c.goType 56} 57 58func (c *listConverter) New() protoreflect.Value { 59 return protoreflect.ValueOfList(&listReflect{reflect.New(c.goType), c.c}) 60} 61 62func (c *listConverter) Zero() protoreflect.Value { 63 return protoreflect.ValueOfList(&listReflect{reflect.Zero(reflect.PtrTo(c.goType)), c.c}) 64} 65 66type listPtrConverter struct { 67 goType reflect.Type // *[]T 68 c Converter 69} 70 71func (c *listPtrConverter) PBValueOf(v reflect.Value) protoreflect.Value { 72 if v.Type() != c.goType { 73 panic(fmt.Sprintf("invalid type: got %v, want %v", v.Type(), c.goType)) 74 } 75 return protoreflect.ValueOfList(&listReflect{v, c.c}) 76} 77 78func (c *listPtrConverter) GoValueOf(v protoreflect.Value) reflect.Value { 79 return v.List().(*listReflect).v 80} 81 82func (c *listPtrConverter) IsValidPB(v protoreflect.Value) bool { 83 list, ok := v.Interface().(*listReflect) 84 if !ok { 85 return false 86 } 87 return list.v.Type() == c.goType 88} 89 90func (c *listPtrConverter) IsValidGo(v reflect.Value) bool { 91 return v.IsValid() && v.Type() == c.goType 92} 93 94func (c *listPtrConverter) New() protoreflect.Value { 95 return c.PBValueOf(reflect.New(c.goType.Elem())) 96} 97 98func (c *listPtrConverter) Zero() protoreflect.Value { 99 return c.PBValueOf(reflect.Zero(c.goType)) 100} 101 102type listReflect struct { 103 v reflect.Value // *[]T 104 conv Converter 105} 106 107func (ls *listReflect) Len() int { 108 if ls.v.IsNil() { 109 return 0 110 } 111 return ls.v.Elem().Len() 112} 113func (ls *listReflect) Get(i int) protoreflect.Value { 114 return ls.conv.PBValueOf(ls.v.Elem().Index(i)) 115} 116func (ls *listReflect) Set(i int, v protoreflect.Value) { 117 ls.v.Elem().Index(i).Set(ls.conv.GoValueOf(v)) 118} 119func (ls *listReflect) Append(v protoreflect.Value) { 120 ls.v.Elem().Set(reflect.Append(ls.v.Elem(), ls.conv.GoValueOf(v))) 121} 122func (ls *listReflect) AppendMutable() protoreflect.Value { 123 if _, ok := ls.conv.(*messageConverter); !ok { 124 panic("invalid AppendMutable on list with non-message type") 125 } 126 v := ls.NewElement() 127 ls.Append(v) 128 return v 129} 130func (ls *listReflect) Truncate(i int) { 131 ls.v.Elem().Set(ls.v.Elem().Slice(0, i)) 132} 133func (ls *listReflect) NewElement() protoreflect.Value { 134 return ls.conv.New() 135} 136func (ls *listReflect) IsValid() bool { 137 return !ls.v.IsNil() 138} 139func (ls *listReflect) protoUnwrap() interface{} { 140 return ls.v.Interface() 141} 142