mirror of
				https://gitea.com/Lydanne/buildx.git
				synced 2025-11-04 18:13:42 +08:00 
			
		
		
		
	
		
			
				
	
	
		
			214 lines
		
	
	
		
			6.4 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			214 lines
		
	
	
		
			6.4 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
// Copyright 2018 The Go Authors. All rights reserved.
 | 
						|
// Use of this source code is governed by a BSD-style
 | 
						|
// license that can be found in the LICENSE file.
 | 
						|
 | 
						|
// Package defval marshals and unmarshals textual forms of default values.
 | 
						|
//
 | 
						|
// This package handles both the form historically used in Go struct field tags
 | 
						|
// and also the form used by google.protobuf.FieldDescriptorProto.default_value
 | 
						|
// since they differ in superficial ways.
 | 
						|
package defval
 | 
						|
 | 
						|
import (
 | 
						|
	"fmt"
 | 
						|
	"math"
 | 
						|
	"strconv"
 | 
						|
 | 
						|
	ptext "google.golang.org/protobuf/internal/encoding/text"
 | 
						|
	"google.golang.org/protobuf/internal/errors"
 | 
						|
	"google.golang.org/protobuf/reflect/protoreflect"
 | 
						|
)
 | 
						|
 | 
						|
// Format is the serialization format used to represent the default value.
 | 
						|
type Format int
 | 
						|
 | 
						|
const (
 | 
						|
	_ Format = iota
 | 
						|
 | 
						|
	// Descriptor uses the serialization format that protoc uses with the
 | 
						|
	// google.protobuf.FieldDescriptorProto.default_value field.
 | 
						|
	Descriptor
 | 
						|
 | 
						|
	// GoTag uses the historical serialization format in Go struct field tags.
 | 
						|
	GoTag
 | 
						|
)
 | 
						|
 | 
						|
// Unmarshal deserializes the default string s according to the given kind k.
 | 
						|
// When k is an enum, a list of enum value descriptors must be provided.
 | 
						|
func Unmarshal(s string, k protoreflect.Kind, evs protoreflect.EnumValueDescriptors, f Format) (protoreflect.Value, protoreflect.EnumValueDescriptor, error) {
 | 
						|
	switch k {
 | 
						|
	case protoreflect.BoolKind:
 | 
						|
		if f == GoTag {
 | 
						|
			switch s {
 | 
						|
			case "1":
 | 
						|
				return protoreflect.ValueOfBool(true), nil, nil
 | 
						|
			case "0":
 | 
						|
				return protoreflect.ValueOfBool(false), nil, nil
 | 
						|
			}
 | 
						|
		} else {
 | 
						|
			switch s {
 | 
						|
			case "true":
 | 
						|
				return protoreflect.ValueOfBool(true), nil, nil
 | 
						|
			case "false":
 | 
						|
				return protoreflect.ValueOfBool(false), nil, nil
 | 
						|
			}
 | 
						|
		}
 | 
						|
	case protoreflect.EnumKind:
 | 
						|
		if f == GoTag {
 | 
						|
			// Go tags use the numeric form of the enum value.
 | 
						|
			if n, err := strconv.ParseInt(s, 10, 32); err == nil {
 | 
						|
				if ev := evs.ByNumber(protoreflect.EnumNumber(n)); ev != nil {
 | 
						|
					return protoreflect.ValueOfEnum(ev.Number()), ev, nil
 | 
						|
				}
 | 
						|
			}
 | 
						|
		} else {
 | 
						|
			// Descriptor default_value use the enum identifier.
 | 
						|
			ev := evs.ByName(protoreflect.Name(s))
 | 
						|
			if ev != nil {
 | 
						|
				return protoreflect.ValueOfEnum(ev.Number()), ev, nil
 | 
						|
			}
 | 
						|
		}
 | 
						|
	case protoreflect.Int32Kind, protoreflect.Sint32Kind, protoreflect.Sfixed32Kind:
 | 
						|
		if v, err := strconv.ParseInt(s, 10, 32); err == nil {
 | 
						|
			return protoreflect.ValueOfInt32(int32(v)), nil, nil
 | 
						|
		}
 | 
						|
	case protoreflect.Int64Kind, protoreflect.Sint64Kind, protoreflect.Sfixed64Kind:
 | 
						|
		if v, err := strconv.ParseInt(s, 10, 64); err == nil {
 | 
						|
			return protoreflect.ValueOfInt64(int64(v)), nil, nil
 | 
						|
		}
 | 
						|
	case protoreflect.Uint32Kind, protoreflect.Fixed32Kind:
 | 
						|
		if v, err := strconv.ParseUint(s, 10, 32); err == nil {
 | 
						|
			return protoreflect.ValueOfUint32(uint32(v)), nil, nil
 | 
						|
		}
 | 
						|
	case protoreflect.Uint64Kind, protoreflect.Fixed64Kind:
 | 
						|
		if v, err := strconv.ParseUint(s, 10, 64); err == nil {
 | 
						|
			return protoreflect.ValueOfUint64(uint64(v)), nil, nil
 | 
						|
		}
 | 
						|
	case protoreflect.FloatKind, protoreflect.DoubleKind:
 | 
						|
		var v float64
 | 
						|
		var err error
 | 
						|
		switch s {
 | 
						|
		case "-inf":
 | 
						|
			v = math.Inf(-1)
 | 
						|
		case "inf":
 | 
						|
			v = math.Inf(+1)
 | 
						|
		case "nan":
 | 
						|
			v = math.NaN()
 | 
						|
		default:
 | 
						|
			v, err = strconv.ParseFloat(s, 64)
 | 
						|
		}
 | 
						|
		if err == nil {
 | 
						|
			if k == protoreflect.FloatKind {
 | 
						|
				return protoreflect.ValueOfFloat32(float32(v)), nil, nil
 | 
						|
			} else {
 | 
						|
				return protoreflect.ValueOfFloat64(float64(v)), nil, nil
 | 
						|
			}
 | 
						|
		}
 | 
						|
	case protoreflect.StringKind:
 | 
						|
		// String values are already unescaped and can be used as is.
 | 
						|
		return protoreflect.ValueOfString(s), nil, nil
 | 
						|
	case protoreflect.BytesKind:
 | 
						|
		if b, ok := unmarshalBytes(s); ok {
 | 
						|
			return protoreflect.ValueOfBytes(b), nil, nil
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return protoreflect.Value{}, nil, errors.New("could not parse value for %v: %q", k, s)
 | 
						|
}
 | 
						|
 | 
						|
// Marshal serializes v as the default string according to the given kind k.
 | 
						|
// When specifying the Descriptor format for an enum kind, the associated
 | 
						|
// enum value descriptor must be provided.
 | 
						|
func Marshal(v protoreflect.Value, ev protoreflect.EnumValueDescriptor, k protoreflect.Kind, f Format) (string, error) {
 | 
						|
	switch k {
 | 
						|
	case protoreflect.BoolKind:
 | 
						|
		if f == GoTag {
 | 
						|
			if v.Bool() {
 | 
						|
				return "1", nil
 | 
						|
			} else {
 | 
						|
				return "0", nil
 | 
						|
			}
 | 
						|
		} else {
 | 
						|
			if v.Bool() {
 | 
						|
				return "true", nil
 | 
						|
			} else {
 | 
						|
				return "false", nil
 | 
						|
			}
 | 
						|
		}
 | 
						|
	case protoreflect.EnumKind:
 | 
						|
		if f == GoTag {
 | 
						|
			return strconv.FormatInt(int64(v.Enum()), 10), nil
 | 
						|
		} else {
 | 
						|
			return string(ev.Name()), nil
 | 
						|
		}
 | 
						|
	case protoreflect.Int32Kind, protoreflect.Sint32Kind, protoreflect.Sfixed32Kind, protoreflect.Int64Kind, protoreflect.Sint64Kind, protoreflect.Sfixed64Kind:
 | 
						|
		return strconv.FormatInt(v.Int(), 10), nil
 | 
						|
	case protoreflect.Uint32Kind, protoreflect.Fixed32Kind, protoreflect.Uint64Kind, protoreflect.Fixed64Kind:
 | 
						|
		return strconv.FormatUint(v.Uint(), 10), nil
 | 
						|
	case protoreflect.FloatKind, protoreflect.DoubleKind:
 | 
						|
		f := v.Float()
 | 
						|
		switch {
 | 
						|
		case math.IsInf(f, -1):
 | 
						|
			return "-inf", nil
 | 
						|
		case math.IsInf(f, +1):
 | 
						|
			return "inf", nil
 | 
						|
		case math.IsNaN(f):
 | 
						|
			return "nan", nil
 | 
						|
		default:
 | 
						|
			if k == protoreflect.FloatKind {
 | 
						|
				return strconv.FormatFloat(f, 'g', -1, 32), nil
 | 
						|
			} else {
 | 
						|
				return strconv.FormatFloat(f, 'g', -1, 64), nil
 | 
						|
			}
 | 
						|
		}
 | 
						|
	case protoreflect.StringKind:
 | 
						|
		// String values are serialized as is without any escaping.
 | 
						|
		return v.String(), nil
 | 
						|
	case protoreflect.BytesKind:
 | 
						|
		if s, ok := marshalBytes(v.Bytes()); ok {
 | 
						|
			return s, nil
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return "", errors.New("could not format value for %v: %v", k, v)
 | 
						|
}
 | 
						|
 | 
						|
// unmarshalBytes deserializes bytes by applying C unescaping.
 | 
						|
func unmarshalBytes(s string) ([]byte, bool) {
 | 
						|
	// Bytes values use the same escaping as the text format,
 | 
						|
	// however they lack the surrounding double quotes.
 | 
						|
	v, err := ptext.UnmarshalString(`"` + s + `"`)
 | 
						|
	if err != nil {
 | 
						|
		return nil, false
 | 
						|
	}
 | 
						|
	return []byte(v), true
 | 
						|
}
 | 
						|
 | 
						|
// marshalBytes serializes bytes by using C escaping.
 | 
						|
// To match the exact output of protoc, this is identical to the
 | 
						|
// CEscape function in strutil.cc of the protoc source code.
 | 
						|
func marshalBytes(b []byte) (string, bool) {
 | 
						|
	var s []byte
 | 
						|
	for _, c := range b {
 | 
						|
		switch c {
 | 
						|
		case '\n':
 | 
						|
			s = append(s, `\n`...)
 | 
						|
		case '\r':
 | 
						|
			s = append(s, `\r`...)
 | 
						|
		case '\t':
 | 
						|
			s = append(s, `\t`...)
 | 
						|
		case '"':
 | 
						|
			s = append(s, `\"`...)
 | 
						|
		case '\'':
 | 
						|
			s = append(s, `\'`...)
 | 
						|
		case '\\':
 | 
						|
			s = append(s, `\\`...)
 | 
						|
		default:
 | 
						|
			if printableASCII := c >= 0x20 && c <= 0x7e; printableASCII {
 | 
						|
				s = append(s, c)
 | 
						|
			} else {
 | 
						|
				s = append(s, fmt.Sprintf(`\%03o`, c)...)
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return string(s), true
 | 
						|
}
 |