...

Source file src/google.golang.org/protobuf/internal/encoding/defval/default.go

Documentation: google.golang.org/protobuf/internal/encoding/defval

     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  
     5  // Package defval marshals and unmarshals textual forms of default values.
     6  //
     7  // This package handles both the form historically used in Go struct field tags
     8  // and also the form used by google.protobuf.FieldDescriptorProto.default_value
     9  // since they differ in superficial ways.
    10  package defval
    11  
    12  import (
    13  	"fmt"
    14  	"math"
    15  	"strconv"
    16  
    17  	ptext "google.golang.org/protobuf/internal/encoding/text"
    18  	"google.golang.org/protobuf/internal/errors"
    19  	"google.golang.org/protobuf/reflect/protoreflect"
    20  )
    21  
    22  // Format is the serialization format used to represent the default value.
    23  type Format int
    24  
    25  const (
    26  	_ Format = iota
    27  
    28  	// Descriptor uses the serialization format that protoc uses with the
    29  	// google.protobuf.FieldDescriptorProto.default_value field.
    30  	Descriptor
    31  
    32  	// GoTag uses the historical serialization format in Go struct field tags.
    33  	GoTag
    34  )
    35  
    36  // Unmarshal deserializes the default string s according to the given kind k.
    37  // When k is an enum, a list of enum value descriptors must be provided.
    38  func Unmarshal(s string, k protoreflect.Kind, evs protoreflect.EnumValueDescriptors, f Format) (protoreflect.Value, protoreflect.EnumValueDescriptor, error) {
    39  	switch k {
    40  	case protoreflect.BoolKind:
    41  		if f == GoTag {
    42  			switch s {
    43  			case "1":
    44  				return protoreflect.ValueOfBool(true), nil, nil
    45  			case "0":
    46  				return protoreflect.ValueOfBool(false), nil, nil
    47  			}
    48  		} else {
    49  			switch s {
    50  			case "true":
    51  				return protoreflect.ValueOfBool(true), nil, nil
    52  			case "false":
    53  				return protoreflect.ValueOfBool(false), nil, nil
    54  			}
    55  		}
    56  	case protoreflect.EnumKind:
    57  		if f == GoTag {
    58  			// Go tags use the numeric form of the enum value.
    59  			if n, err := strconv.ParseInt(s, 10, 32); err == nil {
    60  				if ev := evs.ByNumber(protoreflect.EnumNumber(n)); ev != nil {
    61  					return protoreflect.ValueOfEnum(ev.Number()), ev, nil
    62  				}
    63  			}
    64  		} else {
    65  			// Descriptor default_value use the enum identifier.
    66  			ev := evs.ByName(protoreflect.Name(s))
    67  			if ev != nil {
    68  				return protoreflect.ValueOfEnum(ev.Number()), ev, nil
    69  			}
    70  		}
    71  	case protoreflect.Int32Kind, protoreflect.Sint32Kind, protoreflect.Sfixed32Kind:
    72  		if v, err := strconv.ParseInt(s, 10, 32); err == nil {
    73  			return protoreflect.ValueOfInt32(int32(v)), nil, nil
    74  		}
    75  	case protoreflect.Int64Kind, protoreflect.Sint64Kind, protoreflect.Sfixed64Kind:
    76  		if v, err := strconv.ParseInt(s, 10, 64); err == nil {
    77  			return protoreflect.ValueOfInt64(int64(v)), nil, nil
    78  		}
    79  	case protoreflect.Uint32Kind, protoreflect.Fixed32Kind:
    80  		if v, err := strconv.ParseUint(s, 10, 32); err == nil {
    81  			return protoreflect.ValueOfUint32(uint32(v)), nil, nil
    82  		}
    83  	case protoreflect.Uint64Kind, protoreflect.Fixed64Kind:
    84  		if v, err := strconv.ParseUint(s, 10, 64); err == nil {
    85  			return protoreflect.ValueOfUint64(uint64(v)), nil, nil
    86  		}
    87  	case protoreflect.FloatKind, protoreflect.DoubleKind:
    88  		var v float64
    89  		var err error
    90  		switch s {
    91  		case "-inf":
    92  			v = math.Inf(-1)
    93  		case "inf":
    94  			v = math.Inf(+1)
    95  		case "nan":
    96  			v = math.NaN()
    97  		default:
    98  			v, err = strconv.ParseFloat(s, 64)
    99  		}
   100  		if err == nil {
   101  			if k == protoreflect.FloatKind {
   102  				return protoreflect.ValueOfFloat32(float32(v)), nil, nil
   103  			} else {
   104  				return protoreflect.ValueOfFloat64(float64(v)), nil, nil
   105  			}
   106  		}
   107  	case protoreflect.StringKind:
   108  		// String values are already unescaped and can be used as is.
   109  		return protoreflect.ValueOfString(s), nil, nil
   110  	case protoreflect.BytesKind:
   111  		if b, ok := unmarshalBytes(s); ok {
   112  			return protoreflect.ValueOfBytes(b), nil, nil
   113  		}
   114  	}
   115  	return protoreflect.Value{}, nil, errors.New("could not parse value for %v: %q", k, s)
   116  }
   117  
   118  // Marshal serializes v as the default string according to the given kind k.
   119  // When specifying the Descriptor format for an enum kind, the associated
   120  // enum value descriptor must be provided.
   121  func Marshal(v protoreflect.Value, ev protoreflect.EnumValueDescriptor, k protoreflect.Kind, f Format) (string, error) {
   122  	switch k {
   123  	case protoreflect.BoolKind:
   124  		if f == GoTag {
   125  			if v.Bool() {
   126  				return "1", nil
   127  			} else {
   128  				return "0", nil
   129  			}
   130  		} else {
   131  			if v.Bool() {
   132  				return "true", nil
   133  			} else {
   134  				return "false", nil
   135  			}
   136  		}
   137  	case protoreflect.EnumKind:
   138  		if f == GoTag {
   139  			return strconv.FormatInt(int64(v.Enum()), 10), nil
   140  		} else {
   141  			return string(ev.Name()), nil
   142  		}
   143  	case protoreflect.Int32Kind, protoreflect.Sint32Kind, protoreflect.Sfixed32Kind, protoreflect.Int64Kind, protoreflect.Sint64Kind, protoreflect.Sfixed64Kind:
   144  		return strconv.FormatInt(v.Int(), 10), nil
   145  	case protoreflect.Uint32Kind, protoreflect.Fixed32Kind, protoreflect.Uint64Kind, protoreflect.Fixed64Kind:
   146  		return strconv.FormatUint(v.Uint(), 10), nil
   147  	case protoreflect.FloatKind, protoreflect.DoubleKind:
   148  		f := v.Float()
   149  		switch {
   150  		case math.IsInf(f, -1):
   151  			return "-inf", nil
   152  		case math.IsInf(f, +1):
   153  			return "inf", nil
   154  		case math.IsNaN(f):
   155  			return "nan", nil
   156  		default:
   157  			if k == protoreflect.FloatKind {
   158  				return strconv.FormatFloat(f, 'g', -1, 32), nil
   159  			} else {
   160  				return strconv.FormatFloat(f, 'g', -1, 64), nil
   161  			}
   162  		}
   163  	case protoreflect.StringKind:
   164  		// String values are serialized as is without any escaping.
   165  		return v.String(), nil
   166  	case protoreflect.BytesKind:
   167  		if s, ok := marshalBytes(v.Bytes()); ok {
   168  			return s, nil
   169  		}
   170  	}
   171  	return "", errors.New("could not format value for %v: %v", k, v)
   172  }
   173  
   174  // unmarshalBytes deserializes bytes by applying C unescaping.
   175  func unmarshalBytes(s string) ([]byte, bool) {
   176  	// Bytes values use the same escaping as the text format,
   177  	// however they lack the surrounding double quotes.
   178  	v, err := ptext.UnmarshalString(`"` + s + `"`)
   179  	if err != nil {
   180  		return nil, false
   181  	}
   182  	return []byte(v), true
   183  }
   184  
   185  // marshalBytes serializes bytes by using C escaping.
   186  // To match the exact output of protoc, this is identical to the
   187  // CEscape function in strutil.cc of the protoc source code.
   188  func marshalBytes(b []byte) (string, bool) {
   189  	var s []byte
   190  	for _, c := range b {
   191  		switch c {
   192  		case '\n':
   193  			s = append(s, `\n`...)
   194  		case '\r':
   195  			s = append(s, `\r`...)
   196  		case '\t':
   197  			s = append(s, `\t`...)
   198  		case '"':
   199  			s = append(s, `\"`...)
   200  		case '\'':
   201  			s = append(s, `\'`...)
   202  		case '\\':
   203  			s = append(s, `\\`...)
   204  		default:
   205  			if printableASCII := c >= 0x20 && c <= 0x7e; printableASCII {
   206  				s = append(s, c)
   207  			} else {
   208  				s = append(s, fmt.Sprintf(`\%03o`, c)...)
   209  			}
   210  		}
   211  	}
   212  	return string(s), true
   213  }
   214  

View as plain text