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