convert_list.go

  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() any {
140	return ls.v.Interface()
141}