// Copyright 2015 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 jsonpb

import (
	
	
	
	
	
	
	
	
	
	

	
	
	protoV2 
	
	
)

const wrapJSONMarshalV2 = false

// Marshaler is a configurable object for marshaling protocol buffer messages
// to the specified JSON representation.
type Marshaler struct {
	// OrigName specifies whether to use the original protobuf name for fields.
	OrigName bool

	// EnumsAsInts specifies whether to render enum values as integers,
	// as opposed to string values.
	EnumsAsInts bool

	// EmitDefaults specifies whether to render fields with zero values.
	EmitDefaults bool

	// Indent controls whether the output is compact or not.
	// If empty, the output is compact JSON. Otherwise, every JSON object
	// entry and JSON array value will be on its own line.
	// Each line will be preceded by repeated copies of Indent, where the
	// number of copies is the current indentation depth.
	Indent string

	// AnyResolver is used to resolve the google.protobuf.Any well-known type.
	// If unset, the global registry is used by default.
	AnyResolver AnyResolver
}

// JSONPBMarshaler is implemented by protobuf messages that customize the
// way they are marshaled to JSON. Messages that implement this should also
// implement JSONPBUnmarshaler so that the custom format can be parsed.
//
// The JSON marshaling must follow the proto to JSON specification:
//	https://developers.google.com/protocol-buffers/docs/proto3#json
//
// Deprecated: Custom types should implement protobuf reflection instead.
type JSONPBMarshaler interface {
	MarshalJSONPB(*Marshaler) ([]byte, error)
}

// Marshal serializes a protobuf message as JSON into w.
func ( *Marshaler) ( io.Writer,  proto.Message) error {
	,  := .marshal()
	if len() > 0 {
		if ,  := .Write();  != nil {
			return 
		}
	}
	return 
}

// MarshalToString serializes a protobuf message as JSON in string form.
func ( *Marshaler) ( proto.Message) (string, error) {
	,  := .marshal()
	if  != nil {
		return "", 
	}
	return string(), nil
}

func ( *Marshaler) ( proto.Message) ([]byte, error) {
	 := reflect.ValueOf()
	if  == nil || (.Kind() == reflect.Ptr && .IsNil()) {
		return nil, errors.New("Marshal called with nil")
	}

	// Check for custom marshalers first since they may not properly
	// implement protobuf reflection that the logic below relies on.
	if ,  := .(JSONPBMarshaler);  {
		return .MarshalJSONPB()
	}

	if wrapJSONMarshalV2 {
		 := protojson.MarshalOptions{
			UseProtoNames:   .OrigName,
			UseEnumNumbers:  .EnumsAsInts,
			EmitUnpopulated: .EmitDefaults,
			Indent:          .Indent,
		}
		if .AnyResolver != nil {
			.Resolver = anyResolver{.AnyResolver}
		}
		return .Marshal(proto.MessageReflect().Interface())
	} else {
		// Check for unpopulated required fields first.
		 := proto.MessageReflect()
		if  := protoV2.CheckInitialized(.Interface());  != nil {
			return nil, 
		}

		 := jsonWriter{Marshaler: }
		 := .marshalMessage(, "", "")
		return .buf, 
	}
}

type jsonWriter struct {
	*Marshaler
	buf []byte
}

func ( *jsonWriter) ( string) {
	.buf = append(.buf, ...)
}

func ( *jsonWriter) ( protoreflect.Message, ,  string) error {
	if ,  := proto.MessageV1(.Interface()).(JSONPBMarshaler);  {
		,  := .MarshalJSONPB(.Marshaler)
		if  != nil {
			return 
		}
		if  != "" {
			// we are marshaling this object to an Any type
			var  map[string]*json.RawMessage
			if  = json.Unmarshal(, &);  != nil {
				return fmt.Errorf("type %T produced invalid JSON: %v", .Interface(), )
			}
			,  := json.Marshal()
			if  != nil {
				return fmt.Errorf("failed to marshal type URL %q to JSON: %v", , )
			}
			["@type"] = (*json.RawMessage)(&)
			if ,  = json.Marshal();  != nil {
				return 
			}
		}
		.write(string())
		return nil
	}

	 := .Descriptor()
	 := .Fields()

	// Handle well-known types.
	const  = int64(time.Second / time.Nanosecond)
	switch wellKnownType(.FullName()) {
	case "Any":
		return .marshalAny(, )
	case "BoolValue", "BytesValue", "StringValue",
		"Int32Value", "UInt32Value", "FloatValue",
		"Int64Value", "UInt64Value", "DoubleValue":
		 := .ByNumber(1)
		return .marshalValue(, .Get(), )
	case "Duration":
		const  = 315576000000
		// "Generated output always contains 0, 3, 6, or 9 fractional digits,
		//  depending on required precision."
		 := .Get(.ByNumber(1)).Int()
		 := .Get(.ByNumber(2)).Int()
		if  < - ||  >  {
			return fmt.Errorf("seconds out of range %v", )
		}
		if  <= - ||  >=  {
			return fmt.Errorf("ns out of range (%v, %v)", -, )
		}
		if ( > 0 &&  < 0) || ( < 0 &&  > 0) {
			return errors.New("signs of seconds and nanos do not match")
		}
		var  string
		if  < 0 ||  < 0 {
			, ,  = "-", -1*, -1*
		}
		 := fmt.Sprintf("%s%d.%09d", , , )
		 = strings.TrimSuffix(, "000")
		 = strings.TrimSuffix(, "000")
		 = strings.TrimSuffix(, ".000")
		.write(fmt.Sprintf(`"%vs"`, ))
		return nil
	case "Timestamp":
		// "RFC 3339, where generated output will always be Z-normalized
		//  and uses 0, 3, 6 or 9 fractional digits."
		 := .Get(.ByNumber(1)).Int()
		 := .Get(.ByNumber(2)).Int()
		if  < 0 ||  >=  {
			return fmt.Errorf("ns out of range [0, %v)", )
		}
		 := time.Unix(, ).UTC()
		// time.RFC3339Nano isn't exactly right (we need to get 3/6/9 fractional digits).
		 := .Format("2006-01-02T15:04:05.000000000")
		 = strings.TrimSuffix(, "000")
		 = strings.TrimSuffix(, "000")
		 = strings.TrimSuffix(, ".000")
		.write(fmt.Sprintf(`"%vZ"`, ))
		return nil
	case "Value":
		// JSON value; which is a null, number, string, bool, object, or array.
		 := .Oneofs().Get(0)
		 := .WhichOneof()
		if  == nil {
			return errors.New("nil Value")
		}
		return .marshalValue(, .Get(), )
	case "Struct", "ListValue":
		// JSON object or array.
		 := .ByNumber(1)
		return .marshalValue(, .Get(), )
	}

	.write("{")
	if .Indent != "" {
		.write("\n")
	}

	 := true
	if  != "" {
		if  := .marshalTypeURL(, );  != nil {
			return 
		}
		 = false
	}

	for  := 0;  < .Len(); {
		 := .Get()
		if  := .ContainingOneof();  != nil {
			 = .WhichOneof()
			 += .Fields().Len()
			if  == nil {
				continue
			}
		} else {
			++
		}

		 := .Get()

		if !.Has() {
			if !.EmitDefaults || .ContainingOneof() != nil {
				continue
			}
			if .Cardinality() != protoreflect.Repeated && (.Message() != nil || .Syntax() == protoreflect.Proto2) {
				 = protoreflect.Value{} // use "null" for singular messages or proto2 scalars
			}
		}

		if ! {
			.writeComma()
		}
		if  := .marshalField(, , );  != nil {
			return 
		}
		 = false
	}

	// Handle proto2 extensions.
	if .ExtensionRanges().Len() > 0 {
		// Collect a sorted list of all extension descriptor and values.
		type  struct {
			 protoreflect.FieldDescriptor
			  protoreflect.Value
		}
		var  []
		.Range(func( protoreflect.FieldDescriptor,  protoreflect.Value) bool {
			if .IsExtension() {
				 = append(, {, })
			}
			return true
		})
		sort.Slice(, func(,  int) bool {
			return []..Number() < []..Number()
		})

		for ,  := range  {
			if ! {
				.writeComma()
			}
			if  := .marshalField(., ., );  != nil {
				return 
			}
			 = false
		}
	}

	if .Indent != "" {
		.write("\n")
		.write()
	}
	.write("}")
	return nil
}

func ( *jsonWriter) () {
	if .Indent != "" {
		.write(",\n")
	} else {
		.write(",")
	}
}

func ( *jsonWriter) ( protoreflect.Message,  string) error {
	// "If the Any contains a value that has a special JSON mapping,
	//  it will be converted as follows: {"@type": xxx, "value": yyy}.
	//  Otherwise, the value will be converted into a JSON object,
	//  and the "@type" field will be inserted to indicate the actual data type."
	 := .Descriptor()
	 := .Get(.Fields().ByNumber(1)).String()
	 := .Get(.Fields().ByNumber(2)).Bytes()

	var  protoreflect.Message
	if .AnyResolver != nil {
		,  := .AnyResolver.Resolve()
		if  != nil {
			return 
		}
		 = proto.MessageReflect()
	} else {
		,  := protoregistry.GlobalTypes.FindMessageByURL()
		if  != nil {
			return 
		}
		 = .New()
	}

	if  := protoV2.Unmarshal(, .Interface());  != nil {
		return 
	}

	if wellKnownType(.Descriptor().FullName()) == "" {
		return .marshalMessage(, , )
	}

	.write("{")
	if .Indent != "" {
		.write("\n")
	}
	if  := .marshalTypeURL(, );  != nil {
		return 
	}
	.writeComma()
	if .Indent != "" {
		.write()
		.write(.Indent)
		.write(`"value": `)
	} else {
		.write(`"value":`)
	}
	if  := .marshalMessage(, +.Indent, "");  != nil {
		return 
	}
	if .Indent != "" {
		.write("\n")
		.write()
	}
	.write("}")
	return nil
}

func ( *jsonWriter) (,  string) error {
	if .Indent != "" {
		.write()
		.write(.Indent)
	}
	.write(`"@type":`)
	if .Indent != "" {
		.write(" ")
	}
	,  := json.Marshal()
	if  != nil {
		return 
	}
	.write(string())
	return nil
}

// marshalField writes field description and value to the Writer.
func ( *jsonWriter) ( protoreflect.FieldDescriptor,  protoreflect.Value,  string) error {
	if .Indent != "" {
		.write()
		.write(.Indent)
	}
	.write(`"`)
	switch {
	case .IsExtension():
		// For message set, use the fname of the message as the extension name.
		 := string(.FullName())
		if isMessageSet(.ContainingMessage()) {
			 = strings.TrimSuffix(, ".message_set_extension")
		}

		.write("[" +  + "]")
	case .OrigName:
		 := string(.Name())
		if .Kind() == protoreflect.GroupKind {
			 = string(.Message().Name())
		}
		.write()
	default:
		.write(string(.JSONName()))
	}
	.write(`":`)
	if .Indent != "" {
		.write(" ")
	}
	return .marshalValue(, , )
}

func ( *jsonWriter) ( protoreflect.FieldDescriptor,  protoreflect.Value,  string) error {
	switch {
	case .IsList():
		.write("[")
		 := ""
		 := .List()
		for  := 0;  < .Len(); ++ {
			.write()
			if .Indent != "" {
				.write("\n")
				.write()
				.write(.Indent)
				.write(.Indent)
			}
			if  := .marshalSingularValue(, .Get(), +.Indent);  != nil {
				return 
			}
			 = ","
		}
		if .Indent != "" {
			.write("\n")
			.write()
			.write(.Indent)
		}
		.write("]")
		return nil
	case .IsMap():
		 := .MapKey()
		 := .MapValue()
		 := .Map()

		// Collect a sorted list of all map keys and values.
		type  struct{ ,  protoreflect.Value }
		var  []
		.Range(func( protoreflect.MapKey,  protoreflect.Value) bool {
			 = append(, {.Value(), })
			return true
		})
		sort.Slice(, func(,  int) bool {
			switch .Kind() {
			case protoreflect.BoolKind:
				return ![]..Bool() && []..Bool()
			case protoreflect.Int32Kind, protoreflect.Sint32Kind, protoreflect.Sfixed32Kind, protoreflect.Int64Kind, protoreflect.Sint64Kind, protoreflect.Sfixed64Kind:
				return []..Int() < []..Int()
			case protoreflect.Uint32Kind, protoreflect.Fixed32Kind, protoreflect.Uint64Kind, protoreflect.Fixed64Kind:
				return []..Uint() < []..Uint()
			case protoreflect.StringKind:
				return []..String() < []..String()
			default:
				panic("invalid kind")
			}
		})

		.write(`{`)
		 := ""
		for ,  := range  {
			.write()
			if .Indent != "" {
				.write("\n")
				.write()
				.write(.Indent)
				.write(.Indent)
			}

			 := fmt.Sprint(..Interface())
			,  := json.Marshal()
			if  != nil {
				return 
			}
			.write(string())

			.write(`:`)
			if .Indent != "" {
				.write(` `)
			}

			if  := .marshalSingularValue(, ., +.Indent);  != nil {
				return 
			}
			 = ","
		}
		if .Indent != "" {
			.write("\n")
			.write()
			.write(.Indent)
		}
		.write(`}`)
		return nil
	default:
		return .marshalSingularValue(, , )
	}
}

func ( *jsonWriter) ( protoreflect.FieldDescriptor,  protoreflect.Value,  string) error {
	switch {
	case !.IsValid():
		.write("null")
		return nil
	case .Message() != nil:
		return .marshalMessage(.Message(), +.Indent, "")
	case .Enum() != nil:
		if .Enum().FullName() == "google.protobuf.NullValue" {
			.write("null")
			return nil
		}

		 := .Enum().Values().ByNumber(.Enum())
		if  == nil || .EnumsAsInts {
			.write(strconv.Itoa(int(.Enum())))
		} else {
			.write(`"` + string(.Name()) + `"`)
		}
		return nil
	default:
		switch .Interface().(type) {
		case float32, float64:
			switch {
			case math.IsInf(.Float(), +1):
				.write(`"Infinity"`)
				return nil
			case math.IsInf(.Float(), -1):
				.write(`"-Infinity"`)
				return nil
			case math.IsNaN(.Float()):
				.write(`"NaN"`)
				return nil
			}
		case int64, uint64:
			.write(fmt.Sprintf(`"%d"`, .Interface()))
			return nil
		}

		,  := json.Marshal(.Interface())
		if  != nil {
			return 
		}
		.write(string())
		return nil
	}
}