vendor/google.golang.org/protobuf/internal/encoding/defval/default.go
changeset 256 6d9efbef00a9
child 260 445e01aede7e
equal deleted inserted replaced
255:4f153a23adab 256:6d9efbef00a9
       
     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 	errors "google.golang.org/protobuf/internal/errors"
       
    19 	pref "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 pref.Kind, evs pref.EnumValueDescriptors, f Format) (pref.Value, pref.EnumValueDescriptor, error) {
       
    39 	switch k {
       
    40 	case pref.BoolKind:
       
    41 		if f == GoTag {
       
    42 			switch s {
       
    43 			case "1":
       
    44 				return pref.ValueOfBool(true), nil, nil
       
    45 			case "0":
       
    46 				return pref.ValueOfBool(false), nil, nil
       
    47 			}
       
    48 		} else {
       
    49 			switch s {
       
    50 			case "true":
       
    51 				return pref.ValueOfBool(true), nil, nil
       
    52 			case "false":
       
    53 				return pref.ValueOfBool(false), nil, nil
       
    54 			}
       
    55 		}
       
    56 	case pref.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(pref.EnumNumber(n)); ev != nil {
       
    61 					return pref.ValueOfEnum(ev.Number()), ev, nil
       
    62 				}
       
    63 			}
       
    64 		} else {
       
    65 			// Descriptor default_value use the enum identifier.
       
    66 			ev := evs.ByName(pref.Name(s))
       
    67 			if ev != nil {
       
    68 				return pref.ValueOfEnum(ev.Number()), ev, nil
       
    69 			}
       
    70 		}
       
    71 	case pref.Int32Kind, pref.Sint32Kind, pref.Sfixed32Kind:
       
    72 		if v, err := strconv.ParseInt(s, 10, 32); err == nil {
       
    73 			return pref.ValueOfInt32(int32(v)), nil, nil
       
    74 		}
       
    75 	case pref.Int64Kind, pref.Sint64Kind, pref.Sfixed64Kind:
       
    76 		if v, err := strconv.ParseInt(s, 10, 64); err == nil {
       
    77 			return pref.ValueOfInt64(int64(v)), nil, nil
       
    78 		}
       
    79 	case pref.Uint32Kind, pref.Fixed32Kind:
       
    80 		if v, err := strconv.ParseUint(s, 10, 32); err == nil {
       
    81 			return pref.ValueOfUint32(uint32(v)), nil, nil
       
    82 		}
       
    83 	case pref.Uint64Kind, pref.Fixed64Kind:
       
    84 		if v, err := strconv.ParseUint(s, 10, 64); err == nil {
       
    85 			return pref.ValueOfUint64(uint64(v)), nil, nil
       
    86 		}
       
    87 	case pref.FloatKind, pref.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 == pref.FloatKind {
       
   102 				return pref.ValueOfFloat32(float32(v)), nil, nil
       
   103 			} else {
       
   104 				return pref.ValueOfFloat64(float64(v)), nil, nil
       
   105 			}
       
   106 		}
       
   107 	case pref.StringKind:
       
   108 		// String values are already unescaped and can be used as is.
       
   109 		return pref.ValueOfString(s), nil, nil
       
   110 	case pref.BytesKind:
       
   111 		if b, ok := unmarshalBytes(s); ok {
       
   112 			return pref.ValueOfBytes(b), nil, nil
       
   113 		}
       
   114 	}
       
   115 	return pref.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 pref.Value, ev pref.EnumValueDescriptor, k pref.Kind, f Format) (string, error) {
       
   122 	switch k {
       
   123 	case pref.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 pref.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 pref.Int32Kind, pref.Sint32Kind, pref.Sfixed32Kind, pref.Int64Kind, pref.Sint64Kind, pref.Sfixed64Kind:
       
   144 		return strconv.FormatInt(v.Int(), 10), nil
       
   145 	case pref.Uint32Kind, pref.Fixed32Kind, pref.Uint64Kind, pref.Fixed64Kind:
       
   146 		return strconv.FormatUint(v.Uint(), 10), nil
       
   147 	case pref.FloatKind, pref.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 == pref.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 pref.StringKind:
       
   164 		// String values are serialized as is without any escaping.
       
   165 		return v.String(), nil
       
   166 	case pref.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 }