...

Source file src/google.golang.org/protobuf/internal/protobuild/build.go

Documentation: google.golang.org/protobuf/internal/protobuild

     1  // Copyright 2020 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  
     5  // Package protobuild constructs messages.
     6  //
     7  // This package is used to construct multiple types of message with a similar shape
     8  // from a common template.
     9  package protobuild
    10  
    11  import (
    12  	"fmt"
    13  	"math"
    14  	"reflect"
    15  
    16  	"google.golang.org/protobuf/reflect/protoreflect"
    17  	"google.golang.org/protobuf/reflect/protoregistry"
    18  )
    19  
    20  // A Value is a value assignable to a field.
    21  // A Value may be a value accepted by protoreflect.ValueOf. In addition:
    22  //
    23  // • An int may be assigned to any numeric field.
    24  //
    25  // • A float64 may be assigned to a double field.
    26  //
    27  // • Either a string or []byte may be assigned to a string or bytes field.
    28  //
    29  // • A string containing the value name may be assigned to an enum field.
    30  //
    31  // • A slice may be assigned to a list, and a map may be assigned to a map.
    32  type Value interface{}
    33  
    34  // A Message is a template to apply to a message. Keys are field names, including
    35  // extension names.
    36  type Message map[protoreflect.Name]Value
    37  
    38  // Unknown is a key associated with the unknown fields of a message.
    39  // The value should be a []byte.
    40  const Unknown = "@unknown"
    41  
    42  // Build applies the template to a message.
    43  func (template Message) Build(m protoreflect.Message) {
    44  	md := m.Descriptor()
    45  	fields := md.Fields()
    46  	exts := make(map[protoreflect.Name]protoreflect.FieldDescriptor)
    47  	protoregistry.GlobalTypes.RangeExtensionsByMessage(md.FullName(), func(xt protoreflect.ExtensionType) bool {
    48  		xd := xt.TypeDescriptor()
    49  		exts[xd.Name()] = xd
    50  		return true
    51  	})
    52  	for k, v := range template {
    53  		if k == Unknown {
    54  			m.SetUnknown(protoreflect.RawFields(v.([]byte)))
    55  			continue
    56  		}
    57  		fd := fields.ByName(k)
    58  		if fd == nil {
    59  			fd = exts[k]
    60  		}
    61  		if fd == nil {
    62  			panic(fmt.Sprintf("%v.%v: not found", md.FullName(), k))
    63  		}
    64  		switch {
    65  		case fd.IsList():
    66  			list := m.Mutable(fd).List()
    67  			s := reflect.ValueOf(v)
    68  			for i := 0; i < s.Len(); i++ {
    69  				if fd.Message() == nil {
    70  					list.Append(fieldValue(fd, s.Index(i).Interface()))
    71  				} else {
    72  					e := list.NewElement()
    73  					s.Index(i).Interface().(Message).Build(e.Message())
    74  					list.Append(e)
    75  				}
    76  			}
    77  		case fd.IsMap():
    78  			mapv := m.Mutable(fd).Map()
    79  			rm := reflect.ValueOf(v)
    80  			for _, k := range rm.MapKeys() {
    81  				mk := fieldValue(fd.MapKey(), k.Interface()).MapKey()
    82  				if fd.MapValue().Message() == nil {
    83  					mv := fieldValue(fd.MapValue(), rm.MapIndex(k).Interface())
    84  					mapv.Set(mk, mv)
    85  				} else if mapv.Has(mk) {
    86  					mv := mapv.Get(mk).Message()
    87  					rm.MapIndex(k).Interface().(Message).Build(mv)
    88  				} else {
    89  					mv := mapv.NewValue()
    90  					rm.MapIndex(k).Interface().(Message).Build(mv.Message())
    91  					mapv.Set(mk, mv)
    92  				}
    93  			}
    94  		default:
    95  			if fd.Message() == nil {
    96  				m.Set(fd, fieldValue(fd, v))
    97  			} else {
    98  				v.(Message).Build(m.Mutable(fd).Message())
    99  			}
   100  		}
   101  	}
   102  }
   103  
   104  func fieldValue(fd protoreflect.FieldDescriptor, v interface{}) protoreflect.Value {
   105  	switch o := v.(type) {
   106  	case int:
   107  		switch fd.Kind() {
   108  		case protoreflect.Int32Kind, protoreflect.Sint32Kind, protoreflect.Sfixed32Kind:
   109  			if o < math.MinInt32 || math.MaxInt32 < o {
   110  				panic(fmt.Sprintf("%v: value %v out of range [%v, %v]", fd.FullName(), o, int32(math.MinInt32), int32(math.MaxInt32)))
   111  			}
   112  			v = int32(o)
   113  		case protoreflect.Uint32Kind, protoreflect.Fixed32Kind:
   114  			if o < 0 || math.MaxUint32 < 0 {
   115  				panic(fmt.Sprintf("%v: value %v out of range [%v, %v]", fd.FullName(), o, uint32(0), uint32(math.MaxUint32)))
   116  			}
   117  			v = uint32(o)
   118  		case protoreflect.Int64Kind, protoreflect.Sint64Kind, protoreflect.Sfixed64Kind:
   119  			v = int64(o)
   120  		case protoreflect.Uint64Kind, protoreflect.Fixed64Kind:
   121  			if o < 0 {
   122  				panic(fmt.Sprintf("%v: value %v out of range [%v, %v]", fd.FullName(), o, uint64(0), uint64(math.MaxUint64)))
   123  			}
   124  			v = uint64(o)
   125  		case protoreflect.FloatKind:
   126  			v = float32(o)
   127  		case protoreflect.DoubleKind:
   128  			v = float64(o)
   129  		case protoreflect.EnumKind:
   130  			v = protoreflect.EnumNumber(o)
   131  		default:
   132  			panic(fmt.Sprintf("%v: invalid value type int", fd.FullName()))
   133  		}
   134  	case float64:
   135  		switch fd.Kind() {
   136  		case protoreflect.FloatKind:
   137  			v = float32(o)
   138  		}
   139  	case string:
   140  		switch fd.Kind() {
   141  		case protoreflect.BytesKind:
   142  			v = []byte(o)
   143  		case protoreflect.EnumKind:
   144  			v = fd.Enum().Values().ByName(protoreflect.Name(o)).Number()
   145  		}
   146  	case []byte:
   147  		return protoreflect.ValueOf(append([]byte{}, o...))
   148  	}
   149  	return protoreflect.ValueOf(v)
   150  }
   151  

View as plain text