podman

Форк
0
213 строк · 6.4 Кб
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

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.