package runtime

import (
	
	
	
	
	
	

	
	
)

// JSONPb is a Marshaler which marshals/unmarshals into/from JSON
// with the "google.golang.org/protobuf/encoding/protojson" marshaler.
// It supports the full functionality of protobuf unlike JSONBuiltin.
//
// The NewDecoder method returns a DecoderWrapper, so the underlying
// *json.Decoder methods can be used.
type JSONPb struct {
	protojson.MarshalOptions
	protojson.UnmarshalOptions
}

// ContentType always returns "application/json".
func (*JSONPb) ( interface{}) string {
	return "application/json"
}

// Marshal marshals "v" into JSON.
func ( *JSONPb) ( interface{}) ([]byte, error) {
	var  bytes.Buffer
	if  := .marshalTo(&, );  != nil {
		return nil, 
	}
	return .Bytes(), nil
}

func ( *JSONPb) ( io.Writer,  interface{}) error {
	,  := .(proto.Message)
	if ! {
		,  := .marshalNonProtoField()
		if  != nil {
			return 
		}
		if .Indent != "" {
			 := &bytes.Buffer{}
			if  := json.Indent(, , "", .Indent);  != nil {
				return 
			}
			 = .Bytes()
		}
		_,  = .Write()
		return 
	}

	,  := .MarshalOptions.Marshal()
	if  != nil {
		return 
	}

	_,  = .Write()
	return 
}

var (
	// protoMessageType is stored to prevent constant lookup of the same type at runtime.
	protoMessageType = reflect.TypeOf((*proto.Message)(nil)).Elem()
)

// marshalNonProto marshals a non-message field of a protobuf message.
// This function does not correctly marshal arbitrary data structures into JSON,
// it is only capable of marshaling non-message field values of protobuf,
// i.e. primitive types, enums; pointers to primitives or enums; maps from
// integer/string types to primitives/enums/pointers to messages.
func ( *JSONPb) ( interface{}) ([]byte, error) {
	if  == nil {
		return []byte("null"), nil
	}
	 := reflect.ValueOf()
	for .Kind() == reflect.Ptr {
		if .IsNil() {
			return []byte("null"), nil
		}
		 = .Elem()
	}

	if .Kind() == reflect.Slice {
		if .IsNil() {
			if .EmitUnpopulated {
				return []byte("[]"), nil
			}
			return []byte("null"), nil
		}

		if .Type().Elem().Implements(protoMessageType) {
			var  bytes.Buffer
			if  := .WriteByte('[');  != nil {
				return nil, 
			}
			for  := 0;  < .Len(); ++ {
				if  != 0 {
					if  := .WriteByte(',');  != nil {
						return nil, 
					}
				}
				if  := .marshalTo(&, .Index().Interface().(proto.Message));  != nil {
					return nil, 
				}
			}
			if  := .WriteByte(']');  != nil {
				return nil, 
			}

			return .Bytes(), nil
		}

		if .Type().Elem().Implements(typeProtoEnum) {
			var  bytes.Buffer
			if  := .WriteByte('[');  != nil {
				return nil, 
			}
			for  := 0;  < .Len(); ++ {
				if  != 0 {
					if  := .WriteByte(',');  != nil {
						return nil, 
					}
				}
				var  error
				if .UseEnumNumbers {
					_,  = .WriteString(strconv.FormatInt(.Index().Int(), 10))
				} else {
					_,  = .WriteString("\"" + .Index().Interface().(protoEnum).String() + "\"")
				}
				if  != nil {
					return nil, 
				}
			}
			if  := .WriteByte(']');  != nil {
				return nil, 
			}

			return .Bytes(), nil
		}
	}

	if .Kind() == reflect.Map {
		 := make(map[string]*json.RawMessage)
		for ,  := range .MapKeys() {
			,  := .Marshal(.MapIndex().Interface())
			if  != nil {
				return nil, 
			}
			[fmt.Sprintf("%v", .Interface())] = (*json.RawMessage)(&)
		}
		return json.Marshal()
	}
	if ,  := .Interface().(protoEnum);  && !.UseEnumNumbers {
		return json.Marshal(.String())
	}
	return json.Marshal(.Interface())
}

// Unmarshal unmarshals JSON "data" into "v"
func ( *JSONPb) ( []byte,  interface{}) error {
	return unmarshalJSONPb(, .UnmarshalOptions, )
}

// NewDecoder returns a Decoder which reads JSON stream from "r".
func ( *JSONPb) ( io.Reader) Decoder {
	 := json.NewDecoder()
	return DecoderWrapper{
		Decoder:          ,
		UnmarshalOptions: .UnmarshalOptions,
	}
}

// DecoderWrapper is a wrapper around a *json.Decoder that adds
// support for protos to the Decode method.
type DecoderWrapper struct {
	*json.Decoder
	protojson.UnmarshalOptions
}

// Decode wraps the embedded decoder's Decode method to support
// protos using a jsonpb.Unmarshaler.
func ( DecoderWrapper) ( interface{}) error {
	return decodeJSONPb(.Decoder, .UnmarshalOptions, )
}

// NewEncoder returns an Encoder which writes JSON stream into "w".
func ( *JSONPb) ( io.Writer) Encoder {
	return EncoderFunc(func( interface{}) error {
		if  := .marshalTo(, );  != nil {
			return 
		}
		// mimic json.Encoder by adding a newline (makes output
		// easier to read when it contains multiple encoded items)
		,  := .Write(.Delimiter())
		return 
	})
}

func unmarshalJSONPb( []byte,  protojson.UnmarshalOptions,  interface{}) error {
	 := json.NewDecoder(bytes.NewReader())
	return decodeJSONPb(, , )
}

func decodeJSONPb( *json.Decoder,  protojson.UnmarshalOptions,  interface{}) error {
	,  := .(proto.Message)
	if ! {
		return decodeNonProtoField(, , )
	}

	// Decode into bytes for marshalling
	var  json.RawMessage
	if  := .Decode(&);  != nil {
		return 
	}

	return .Unmarshal([]byte(), )
}

func decodeNonProtoField( *json.Decoder,  protojson.UnmarshalOptions,  interface{}) error {
	 := reflect.ValueOf()
	if .Kind() != reflect.Ptr {
		return fmt.Errorf("%T is not a pointer", )
	}
	for .Kind() == reflect.Ptr {
		if .IsNil() {
			.Set(reflect.New(.Type().Elem()))
		}
		if .Type().ConvertibleTo(typeProtoMessage) {
			// Decode into bytes for marshalling
			var  json.RawMessage
			if  := .Decode(&);  != nil {
				return 
			}

			return .Unmarshal([]byte(), .Interface().(proto.Message))
		}
		 = .Elem()
	}
	if .Kind() == reflect.Map {
		if .IsNil() {
			.Set(reflect.MakeMap(.Type()))
		}
		,  := convFromType[.Type().Key().Kind()]
		if ! {
			return fmt.Errorf("unsupported type of map field key: %v", .Type().Key())
		}

		 := make(map[string]*json.RawMessage)
		if  := .Decode(&);  != nil {
			return 
		}
		for ,  := range  {
			 := .Call([]reflect.Value{reflect.ValueOf()})
			if  := [1].Interface();  != nil {
				return .(error)
			}
			 := [0]
			 := reflect.New(.Type().Elem())
			if  == nil {
				 := json.RawMessage("null")
				 = &
			}
			if  := unmarshalJSONPb([]byte(*), , .Interface());  != nil {
				return 
			}
			.SetMapIndex(, .Elem())
		}
		return nil
	}
	if .Kind() == reflect.Slice {
		if .Type().Elem().Kind() == reflect.Uint8 {
			var  []byte
			if  := .Decode(&);  != nil {
				return 
			}
			if  != nil {
				.SetBytes()
			}
			return nil
		}

		var  []json.RawMessage
		if  := .Decode(&);  != nil {
			return 
		}
		if  != nil {
			.Set(reflect.MakeSlice(.Type(), 0, 0))
		}
		for ,  := range  {
			 := reflect.New(.Type().Elem())
			if  := unmarshalJSONPb([]byte(), , .Interface());  != nil {
				return 
			}
			.Set(reflect.Append(, .Elem()))
		}
		return nil
	}
	if ,  := .Interface().(protoEnum);  {
		var  interface{}
		if  := .Decode(&);  != nil {
			return 
		}
		switch v := .(type) {
		case string:
			// TODO(yugui) Should use proto.StructProperties?
			return fmt.Errorf("unmarshaling of symbolic enum %q not supported: %T", , .Interface())
		case float64:
			.Set(reflect.ValueOf(int32()).Convert(.Type()))
			return nil
		default:
			return fmt.Errorf("cannot assign %#v into Go type %T", , .Interface())
		}
	}
	return .Decode()
}

type protoEnum interface {
	fmt.Stringer
	EnumDescriptor() ([]byte, []int)
}

var typeProtoEnum = reflect.TypeOf((*protoEnum)(nil)).Elem()

var typeProtoMessage = reflect.TypeOf((*proto.Message)(nil)).Elem()

// Delimiter for newline encoded JSON streams.
func ( *JSONPb) () []byte {
	return []byte("\n")
}

var (
	convFromType = map[reflect.Kind]reflect.Value{
		reflect.String:  reflect.ValueOf(String),
		reflect.Bool:    reflect.ValueOf(Bool),
		reflect.Float64: reflect.ValueOf(Float64),
		reflect.Float32: reflect.ValueOf(Float32),
		reflect.Int64:   reflect.ValueOf(Int64),
		reflect.Int32:   reflect.ValueOf(Int32),
		reflect.Uint64:  reflect.ValueOf(Uint64),
		reflect.Uint32:  reflect.ValueOf(Uint32),
		reflect.Slice:   reflect.ValueOf(Bytes),
	}
)